implicit destructors and assignment operators (C++)

Simpson, Kenny Kenny.Simpson@gs.com
Fri Dec 1 07:37:00 GMT 2000


Hi,
  The following little test program shows unusual behavior.
The first problem is that the excpetion specs for virtual destructors seems
to be ignored.
The first example is almost straight from an example in the Standard.

  The second problem is that the wrong operator= seems the be generated, and
even the generated
operator= has very odd behavior.  The dangerous problem is that a non-const
operator= is called
in the base, when a const operator= is invoked on the derived class.
  The resulting implicit operator= seems to be something like:

Derived& operator=(Derived const& rhs) { return
Base::operator=(const_cast<Derived&>(rhs));}

  The implicit const_cast is what I find dangerous.  I tried the same code
on another compiler and
got different results.

Thanks,
-Kenny

(speaking only for myself, not my employer)

implicit_test.cpp:

// test implicit destructor generation
namespace destructor_tests
{

struct B1
{
  virtual ~B1() throw(int) {}
};

struct B2
{
  virtual ~B2() throw(char) {}
};

struct D12 : public B1, public B2
{
  // implicit destructor should be "inline virtual ~D12() throw(int, char)
{}", which should not compile as it is less restrictive than ~B1 and ~B2
};

class D1 : public B1
{
  // implicit destructor should be sane as for ~D12()
  B2 b2;
};

struct NTB // no-throw base
{
  virtual ~NTB() throw() {}
};

struct DNTB
{
  ~DNTB() {} // should not compile as ~DNTB is less restrictive than ~NTB()
};

struct INTB : public NTB
{
  // implicitly declare "inline virtual ~INTB() throw() {}"
};

struct DINTB : public INTB
{
  ~DINTB() {} // should not compile as it is less restrictive than ~INTB
};

} // end of namespace destructor_tests

#include <iostream> // for std::cout

namespace assign_oper_tests
{

  struct B
  {
	B& operator=(B&) { std::cout << "B::operator=(B&)" << std::endl;
return *this;}
	B& operator=(B const&) { std::cout << "B::operator=(B const&)" <<
std::endl; return *this;}
  };

  struct D : public B
  {
	D() {} // const objects with no members need to explicitly define a
default constructor - wierd
	// implicitly define D& operator=(D const& rhs) { return
B::operator=(rhs);}
	// implicitly define D& operator=(D& rhs)       { return
B::operator=(rhs);}
  };

  struct NCB // non-const only
  {
	NCB& operator=(NCB&) { std::cout << "NCB::operator=(NCB&)" <<
std::endl; return *this;}
  };

  struct DNCB : public NCB
  {
	DNCB() {} // const objects with no members need to explicitly define
a default constructor - wierd
	// implicitly define DNCB& operator=(DNCB& rhs) { return
NCB::operator=(rhs);}
  };

}

void test_destructors()
{
  using namespace destructor_tests;
  D1 d1;
  D12 d12;
  DNTB dntb;
  DINTB dintb;
}

void test_assign_oper()
{
  using namespace assign_oper_tests;
  {
	D d1;
	D d2;
	d2 = d1;  // should print "B::operator=(B&) ?       / gcc -
B::operator=(B&) / other - B::operator=(B const&)"
	
	D const cd1;
	d1 = cd1; // should print "B::operator=(B const&) ? / gcc -
B::operator=(B&) / other - B::operator=(B const&)"
  }
  {
	DNCB d1;
	DNCB d2;
	d2 = d1; // should print "NCB::operator=(NCB&)"

	DNCB const cd1;
	//d1 = cd1; // should not compile! - and doesn't - good
  }
};

int main()
{
  test_destructors();
  test_assign_oper();
  return 0;
}


More information about the Gcc-bugs mailing list