Re: Will a constructor be able to "call" a constructor in C++0x?
On Aug 22, 4:26 am, "Bo Persson" <b...@gmb.dk> wrote:
joe wrote:
The subject is the question. Furthering, doesn't it make sense to
consolidate code in a "main" constructor and have other ones use it
to provide different instantiation ways for a class? (rhetorical, I
think, because I think so). It's all about providing a rich class
instantiation interface to users (programmers) while having
maintainable and reliable source code, and allowing one constructor
to "call" another (quotes used because I just want the capability
and am not too worried about the syntax) gives exactly that.
Yes, it is called a "delegating constructor" when one constructor has
another constructor of the same class in its initializer list.
struct C
{
C( int ) { } // #1: non-delegating constructor
C(): C(42) { } // #2: delegates to #1
};
Imho, this is one of the more exciting features in C++0X, and not just
because it allows you to consolidate initialization code. I like it
for its ability to make writing exception safe code so much easier.
For example consider a class C which holds two resources (I'll just
use int pointers for ease of demonstration). Such a class in C++03
might be coded like this:
class C
{
int* data1_;
int* data2_;
public:
C() : data1_(0), data2_(0) {}
C(int i, int j)
: data1_(0), data2_(0) {}
{
try
{
data1_ = new int(i);
data2_ = new int(j);
}
catch (...)
{
delete data1_;
throw;
}
}
C(const C& c)
: data1_(0), data2_(0) {}
{
try
{
if (c.data1_)
data1_ = new int(*c.data1_);
if (c.data2_)
data2_ = new int(*c.data2_);
}
catch (...)
{
delete data1_;
throw;
}
}
~C()
{
delete data1_;
delete data2_;
}
}
Note the need to wrap the non-default constructors up with try-catch-
rethrow.
Delegating constructors have the property that once /any/ constructor
completes, the class is considered constructed, and thus its
destructor must run when the class goes out of scope. This means that
now the non-default constructors can rely on the default constructor
to construct the class, and after that, they can count on the
destructor to run if they throw an exception:
class C
{
int* data1_;
int* data2_;
public:
C() : data1_(nullptr), data2_(nullptr) {}
C(int i, int j)
: C()
{
data1_ = new int(i);
data2_ = new int(j);
}
C(const C& c)
: C()
{
if (c.data1_)
data1_ = new int(*c.data1_);
if (c.data2_)
data2_ = new int(*c.data2_);
}
~C()
{
delete data1_;
delete data2_;
}
}
Delegating constructors just really cleans up the code to deal with
exception safety, at least for those types that can delegate to a
resource-less constructor! :-)
-Howard