Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constructor initialization lists order/allocation question

My question is simple, is the next code safe?

struct Parent {
    B* _a;
    Parent(B* a) : _a(a) {}
};

struct Child : public Parent {
    B _b;
    Child() : Parent(&_b),  _b(2){};
};

int main() {
    Child c;
    return 0;
}

Two more points:

  • I am interested in the part of passing a reference to a member object to the parent.
  • By safe I mean that _b will be allocated (and its memory address) and that this code will work regardless of which compiler I use.

Thanks in advance.

clarification
by safe I actually meant that the memory address was valid, since I already knew It was not initialized.

other notes
In my actual code I wanted to store the object of type B as a pointer to its base class A, like this:

struct Parent {
    A* _a;
    Parent(A* a) : _a(a) {}
};

struct Child : public Parent {
    B _b;
    Child() : Parent(&_b),  _b(2){};
};

int main() {
    Child c;
    return 0;
}

Which, if I understand AndreyT answer correctly, is illegal. I guess I'll try to do this differently, since this approach was error prone. (I might forget that I couldn't use that pointer and do something with it in my next refactor).

like image 730
João Portela Avatar asked Nov 05 '10 17:11

João Portela


People also ask

Should my constructors use initialization lists or assignment?

Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment. Note: There is no performance difference if the type of x_ is some built-in/intrinsic type, such as int or char* or float .

What is constructor initialization list?

Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.

When using initializer lists in what order are member variables initialized?

Const member variables must be initialized. A member initialization list can also be used to initialize members that are classes. When variable b is constructed, the B(int) constructor is called with value 5. Before the body of the constructor executes, m_a is initialized, calling the A(int) constructor with value 4.

Does initializer list run before constructor?

The initializer list is used to directly initialize data members of a class. An initializer list starts after the constructor name and its parameters.


3 Answers

In the sense that you describe, yes it is safe: the memory is allocated and it is perfectly fine to pass that pointer to the parent. The memory for Child::_b is actually integral part of the memory of the entire Child. It doesn't require any explicit additional "allocations". By the moment the Child::Child constructor is invoked, the memory is obviously already there.

However, the memory the pointer points to can only be used in number of limited ways (the standard describes in 3.8 what can and what cannot be done with it), since the object it points to has not been initialized yet. In your specific example you simply store the pointer. That is perfectly OK.

But if you, for example, wanted to convert that pointer to some base class type (assuming for a second that B has some base class), you code would be illegal. It is illegal to convert pointers to uninitialized objects to their base class pointers (again, see 3.8).

like image 188
AnT Avatar answered Oct 24 '22 03:10

AnT


The order of initialization is as follows:

// Base classes:
Parent(&_b)

// Members:
_b(2)

// Constructor Body:
Child() { }

Whether this is safe depends on your definition of "safe." By your definition ("will it work?"), yes, it is safe. The lifetime of Child::_b begins when the Child object is created, so you can obtain a pointer to it and that pointer refers to an object. However, you can't use the pointed-to value until after _b is initialized, which is after the constructor of the base class, Parent, has returned.

like image 28
James McNellis Avatar answered Oct 24 '22 04:10

James McNellis


The parent constructor will be called first and you will be passing the address of an unitiliazed member variable to that constructor. It's not safe.

edit:

I think AndreyT stated more clearly and more vividly the type of problems that sprang to mind when I wrote my answer. Those are the types of errors that aren't immediately perceivable. The kind that will keep you up at night attempting to figure out where the dangling pointer exists in your code or where the memory corruption is occurring.

like image 1
wheaties Avatar answered Oct 24 '22 05:10

wheaties