[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::c_plus_plus

Title:C++
Notice:Read 1.* and use keywords (e.g. SHOW KEY/FULL KIT_CXX_VAX_VMS)
Moderator:DECCXX::AMARTIN
Created:Fri Nov 06 1987
Last Modified:Thu Jun 05 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3604
Total number of notes:18242

3531.0. "C++ questions..." by HYDRA::LNARAYAN () Tue Apr 08 1997 14:56

    Hello
    
    Here is a mesage from a partner, he is using C++ 5.5 and Digital 
    UNIX 4.0b on a 8400 5/350. Can somehelp on these? He says ...
    
    Thanks In Advance
    Lakshminarayanan

Digital C++ Peculiarities
=====================================


1)  Compiler may optimize-out side effects of a statement when a
    templatized type has an empty destructor!!

    EXAMPLE from List<T>

    while (size) {		// destroy each element of the array
       array[--size].~T();
    }

    Produces an infinite loop if T is int:

   
    WORKAROUND:

    Make templatized destructor call side-effect free:

    while (size) {		// destroy each element of the array
      --size;
       array[size].~T();
    }


2) templates parameter names must match exactly

   EXAMPLE:
	template <class KEY, class VALUE>
	class Hash {
	public:
	  Hash( const KEY& k, const VALUE& v);
	};

	template <class K, class V>
	Hash<K,V>::Hash( const K& k, const V& v) {
	}

	
    averto.cogit.com:185% cxx Temp.cc
	cxx: Error: Temp.cc, line 8: Missing ")".
	Hash<K,V>::Hash( const K& k, const V& v) {
	------------------------^

    Changing "KEY" to "K" solves the problem.

    WORKAROUND:
	Use consistent names for template parameters everywhere.

3)  Inheritance of certain functions doesn't seem to work.  (this
    needs furtheer characterization!)

    EXAMPLE:
#include <stdio.h>
#include <assert.h>

struct foo {
  foo(int y) : x(y) {};
  int x;
};

class FooPtr_Base {
public:
  
#ifdef BUG  
  int operator!() const { return p == 0; }
#endif
  
  ~FooPtr_Base() { printf( "destructor called\n"); delete p; }
  FooPtr_Base() : p(0) {}
  foo* p;
};

class FooPtr : public FooPtr_Base {
public:

#ifndef BUG  
  int operator!() const { return p == 0; }
#endif
  
  FooPtr(foo* pf) {
    p = pf;
  }
  
  FooPtr(const FooPtr& src){
    p = src.p;
    printf("copy constructor called\n");
    (foo* &)src.p = 0;
  }
};

extern FooPtr f( FooPtr b );

int main (int , char **argv) {
  FooPtr l5(new foo(2));
  FooPtr q( f(l5 ));
  
  assert(!l5);
  return 0;
}

averto.cogit.com:886% sh -x inhb
+ cxx -UBUG -w0 -g -nocleanup -O0 -inline none InheritanceBug.cc -o InheritanceBug 
+ InheritanceBug 
copy constructor called
destructor called
destructor called
destructor called
+ cxx -DBUG -w0 -g -nocleanup -O0 -inline none InheritanceBug.cc -o InheritanceBug 
+ InheritanceBug 
Assertion failed: !l5, file InheritanceBug.cc, line 45


	WORKAROUND:
	In this case, moving operator= down a level solves the problem.
	Unfortunately, we don't know why this happens, so the cure is
	magic and may not be a general remedy.  The above example was
	derived from SafePtr<T> (tSafePtr originally demonstrated the
	problem).

4)  -O0 doesn't seem to turn off all optimzation.

    EXAMPLE:
	#include <stdio.h>
        #include <assert.h>
	
	class XXXX {
	public:
	  XXXX() { x = 0; }
	  XXXX( const XXXX& );
	  XXXX& operator = (const XXXX&);
	  int x;
	};
	
	inline
	XXXX::XXXX( const XXXX& y) {
	  printf("Copy called\n");
	  x = y.x+1;
	}
	
	inline
	XXXX& XXXX::operator=( const XXXX& y) {
	  printf("Assignment called\n");
	  x = y.x;
	  return *this;
	}
	
	XXXX f ( XXXX a, XXXX b, XXXX c) {
	  b = c;
	  a = b;
	  return a;
	}
	
	int main() {
	  XXXX x1, x2, x3;
	
	  XXXX y = f(x1,x2,x3) ;
	  assert(x1.x == 0);
	  assert(x2.x == 0);
	  // assert(x3.x == 0);
	  return y.x - 2;
	}
	
    The copy constructor/destructor calls for x3 are optimized out even
    when -O0 is on the command line.  This lead us down a wild goose chase
    looking for bug #3.

    WORKAROUND:
	?????

5) templates must be in header files, along with any classes or
   definitions that template relies on.

   EXAMPLE:

	template <class T>
	class XXX {
	public:
	  static XXX<T> * & root();
	};

	template <class T> XXX<T> * &
	XXX<T>::root()
	{
	    static XXX<T> *the_root = 0;
	    return( the_root );
	}

	int 
	main()
	{
	    XXX<int>** y = &XXX<int>::root();
	    assert( &XXX<int>::root() == y );
	    assert( (void *)&XXX<double>::root() != (void *)y );
	}


    Does not link:

	cxx -g3 -nocleanup -L../lib -L/proj/cogit/build/mainline/digital-gnu/\
	lib -o t-platform t-platform.o 
	cxx: Error: ./cxx_repository/XXX__Td.cxx, line 4: Invalid declaration.
	typedef XXX<double > __dummy_;
	-----------^
	cxx: Error: ./cxx_repository/XXX__Ti.cxx, line 4: Invalid declaration.
	typedef XXX<int > __dummy_;
	-----------^
	ld:
	Unresolved:
	XXX<int>::root(void)
	XXX<double>::root(void)
	make: *** [t-platform] Error 1

    Moving the template declarations into a header solves the problem.

    WORKAROUND:
	All template class (and function?) definitions must be in headers.
        Or use some unfortunate combination of options (like
        -tlocal).

==========================
    
    
T.RTitleUserPersonal
Name
DateLines
3531.1reponse to #2, 4, and 5DECCXX::MITCHELLThu Apr 10 1997 21:1325
I've responded to three of your queries.  Others will respond to the
other two.  We would be interested in having this partner field test V6.0.
We plan to start field test this summer.


>2) templates parameter names must match exactly

The workaround is as stated.  This is fixed in V6.0.

>4)  -O0 doesn't seem to turn off all optimzation.
>
>    The copy constructor/destructor calls for x3 are optimized out even
>    when -O0 is on the command line.  This lead us down a wild goose chase
>    looking for bug #3.

This was done to provide a consistent semantic meaning with and without
optimization.  I've noted a suggestion to provide a way to disable
optimization of copy ctor/dtor calls.

>5) templates must be in header files, along with any classes or
>   definitions that template relies on.
>
The workaround is as stated.  Yes, this is a documented restriction of the
automatic instantiation implementation for V5.n.  We plan to lift this
restriction in V6.0.
3531.2DECCXL::KAOFri Apr 11 1997 13:4220
Re .0 item 1)

>    while (size) {		// destroy each element of the array
>       array[--size].~T();
>    }
>
>    Produces an infinite loop if T is int:

If the size is a negative number, then it shall run into loop.
However, you also mentioned that the following workaround:

>    while (size) {		// destroy each element of the array
>      --size;
>       array[size].~T();
>    }

It more likely a bug somewhere then.
We would like to look into this case, please provide us a small test that
could demonstrate this loop problem.
Thanks.
3531.3DECCXL::KAOFri Apr 11 1997 14:3143
Re .0 item 3)

>+ cxx -DBUG -w0 -g -nocleanup -O0 -inline none InheritanceBug.cc -o
>InheritanceBug 
>+ InheritanceBug 
>Assertion failed: !l5, file InheritanceBug.cc, line 45
>
>
>	WORKAROUND:
>	In this case, moving operator= down a level solves the problem.
>	Unfortunately, we don't know why this happens, so the cure is
>	magic and may not be a general remedy.  The above example was
>	derived from SafePtr<T> (tSafePtr originally demonstrated the
>	problem).

I thought it was similar to C_PLUS_PLUS:3361 (Code fixed at 10-Dec-1996).
I could not reproduce the same problem from your source posted at item 3)
on both compiler: 
	DEC C++ V5.5-004 on Digital UNIX (Alpha)
	DEC CXX X5.6-130 on Digital UNIX (Alpha)

shijun.zko.dec.com> cxx -DBUG -w0 -g -nocleanup -O0 -inline none cpp3531c.cxx
ld:
Unresolved:
f(FooPtr)
shijun.zko.dec.com> $CEXE/deccxx_driver -DBUG -w0 -g -nocleanup -O0 -inline none
cpp3531c.cxx
ld:
Unresolved:
f(FooPtr)

After I provided the definition to the "f(FooPtr)" as {return b;},
the code ran fine from both compilers.
shijun.zko.dec.com> a.out
copy constructor called
copy constructor called
destructor called
destructor called
destructor called

Please provide us a test that can show this problem, we want to look into it 
if is not the same as 3361.

3531.4Thank YouHYDRA::LNARAYANMon Apr 14 1997 16:486
    Hello
    
    Thank you very much for your help. I have asked the partner to
    provide examples case 1 and 3.
    
    -Lakshminarayan
3531.5example codeHYDRA::LNARAYANMon Apr 14 1997 21:38127
> 
> >    while (size) {		// destroy each element of the array
> >       array[--size].~T();
> >    }
> >
> >    Produces an infinite loop if T is int:
> 
> If the size is a negative number, then it shall run into loop.

Obviously, but size is not a negative number.  This code works on all
other compilers we use.  

>            please provide us a small test that could demonstrate
> this loop problem.

Happy to:

#include <stdio.h>
#include <new.h>
#include <assert.h>

template <class T>
class List {
    int max_size;
    int size;
    T   *array;  
public:

    int length() { return( size ); }
    T &elem( int i ) { assert( i < size ); return( array[i] ); }
    void *operator new( size_t, void *place ) { return( place ); }

    void append( const T &x ) {
        assert( size < max_size );
        new (& array[size]) T( x ); 
        ++size;
    }

    List() : max_size( 8 ), size( 0 )  { 
        array = (T *) new char[sizeof( T ) * max_size];
    }

    ~List() {
        while( size > 0 ) 
            array[--size].~T();
    }
};

int
main()
{
    printf( "List start\n" );
    {
        List<int> li;
        int i;
        for( i = 0; i < 4; ++i )
            li.append( i * i );
        for( i = 0; i < 4; ++i )
            printf( "%d => %d\n", i, li.elem( i ) );
    }
    printf( "List end\n" );
}
        
> item 3)
> 
> >+ cxx -DBUG -w0 -g -nocleanup -O0 -inline none InheritanceBug.cc -o
> After I provided the definition to the "f(FooPtr)" as {return b;},
> the code ran fine from both compilers.

Try: { return new foo(0); }

#include <stdio.h>
#include <assert.h>

struct foo {
  foo(int y) : x(y) {};
  int x;
};

class FooPtr_Base {
public:
  
#ifdef BUG  
  int operator!() const { return p == 0; }
#endif
  
  ~FooPtr_Base() { printf( "destructor called\n"); delete p; }
  FooPtr_Base() : p(0) {}
  foo* p;
};

class FooPtr : public FooPtr_Base {
public:

#ifndef BUG  
  int operator!() const { return p == 0; }
#endif
  
  FooPtr(foo* pf) {
    p = pf;
  }
  
  FooPtr(const FooPtr& src){
    p = src.p;
    printf("copy constructor called\n");
    (foo* &)src.p = 0;
  }
};

extern FooPtr f( FooPtr b );

int main (int , char **argv) {
  FooPtr l5(new foo(2));
  FooPtr q( f(l5 ));
  
  assert(!l5);
  return 0;
}


FooPtr 
f( FooPtr b )
{
    return new foo(0);
}

    
3531.6Thanks for the reproducerCXXC::REINIGThis too shall changeTue Apr 15 1997 14:184
I've verified that the small test program in the previous reply reproduces
the problem and have noted it in our internal bug tracking system.

                                August G. Reinig
3531.7Problem item 3 has been fixed...DECC::KAOTue Apr 15 1997 14:5812
Thanks for your tests.
Since August already noted the problem into the bug tracking system,
I just want to clarify the following:

Your workaround on item 1, the loop problem is correct.

Item 3:

>Assertion failed: !l5, file InheritanceBug.cc, line 45

This problem has been fixed in our next release of DEC C++ V5.6
compiler.  Its field test release for UNIX will be available in a week or so.