Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ constructors fun - constructing Foo with a copy of itself

I have:

class Foo;

class Bar {
  Foo foo;
  Bar(): foo(foo) {};
}

Bar bar;

At this point, is

bar.foo // <--- how is this initialized?

[This question arose from a buggy ref-counted pointer implemntation; I could have sworn that I ensured each pointer was pointing at something non-null; but I ended up with a pointer that pointed at something NULL.]

like image 970
anon Avatar asked Feb 24 '10 19:02

anon


1 Answers

foo is fully initialized once you've entered the body of the constructor (that's the guaranteed general case; specifically once it has finished initializing in the initialize list.)

In your case, you are copy-constructing from a non-constructed object. This results in undefined behavior, per §12.7/1 (thank you, gf):

For an object of non-POD class type (clause 9), before the constructor begins execution and after the destructor finishes execution, referring to any nonstatic member or base class of the object results in undefined behavior.

In fact, it gives this example:

struct W { int j; };
struct X : public virtual W { };
struct Y {
    int *p;
    X x;
    Y() : p(&x.j) // undefined, x is not yet constructed
    { }
};

Note, the compiler is not required to give a diagnosis of undefined behavior, per §1.4/1. While I think we all agree it would be nice, it simply isn't something the compiler implementers need to worry about.


Charles points out a loophole of sorts. If Bar has static storage and if Foo is a POD type, then it will be initialized when this code runs. Static-stored variables are zero-initialized before an other initialization runs.

This means whatever Foo is, as long as it doesn't need a constructor to be run to be initialized (i.e., be POD) it's members will be zero-initialized. Essentially, you'll be copying a zero-initialized object.

In general though, such code is to be avoided. :)

like image 82
GManNickG Avatar answered Oct 16 '22 23:10

GManNickG