Reputation: 81
Is the constructor Year() safe in this case ?
struct Year {
int year;
Year(int y) : year(y) {}
Year() { *this = Year(1970); } // *this = this->operator=(Year(1970));
};
Year y;
I think yes, because year has already been initialized with int() once the execution flows reaches the constructor body. Are there other problems to consider?
Don't consider other cases in which the same trick might cause troubles.
Upvotes: 4
Views: 180
Reputation: 385174
Sure, this will work, and is valid.
All data members and bases have already been constructed by the time your ctor-body runs, and:
[n3290: 12.7/4]
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). [..]
Not to be confused with:
[n3290: 12.7/1]
For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior.
(NB. "before the constructor begins"; this clause does not apply here.)
And there's nothing in 12.8 "Copying and moving class objects"
to prohibit assignment during construction.
Note that this does not mean that the object has begun its "lifetime":
[n3290: 3.8/1]:
The lifetime of an object of typeT
begins when:
- storage with the proper alignment and size for type
T
is obtained, and- if the object has non-trivial initialization, its initialization is complete.
And the final step in "initialization" for a non-delegating ctor:
[n3290: 12.6.2/10]:
[..] Finally, the compound-statement of the constructor body is executed.
Put altogether, this means that an object's "lifetime" doesn't begin until its most derived constructor body has finished executing.
In particular, passing a pointer to the object before it has started its life is not very useful, as doing almost anything through that pointer invokes Undefined Behaviour:
[n3290: 3.5/8]:
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. [..]
However:
[n3290: 3.8/3]:
[..] [ Note: [..] Also, the behavior of an object under construction and destruction might not be the same as the behavior of an object whose lifetime has started and not ended. 12.6.2 and 12.7 describe the behavior of objects during the construction and destruction phases. —end note ]
And, as we've already explored, 12.7
kindly informs us that members may be accessed during this phase of construction.
Your approach is hard to follow, though; I also had to look up the above passage before I could be sure that it's valid, so it's clearly not entirely intuitive.
Fortunately C++0x introduces constructor delegation, so that you can write:
struct Year {
Year() : Year(1970) {}
Year(int y) : year(y) {}
int year;
};
(Alas, GCC 4.5.1 doesn't support this, so I cannot demonstrate it to you on ideone.com. In fact, for GCC as a whole there's only a "partial patch" at time of writing.)
Upvotes: 5
Reputation: 477070
This answer is probably wrong; see Tomalak's answer and the comments. I'll leave it for historic reasons, but you're probably OK calling member functions during the constructor.
Most definitely not. If you have any T*
, say p
, then you may only invoke member functions via p->
if p
points to an object. But an object only begins its life when its constructor has finished. So while you're in the middle of the constructor, this
does not point to an object! Therefore, you can most certainly not invoke any member functions like the assignment operator on this not-yet object.
[Curiosum: It is legit to say delete this;
in certain situations, you just have to make sure that the destructor does not refer to this
in any way. It is also OK to pass this
to some other place during the constructor, as long as it is not dereferenced, much like you can pass any garbage pointer around as long as you don't use it.]
Upvotes: 0
Reputation: 32510
What you're doing works, but what wouldn't work would be if you somehow recursively called a constructor ... that would cause problems. But since the constructor is called after all non-static data-members of the object have been constructed, and the this
pointer is pointing to valid memory that can be copied into, what you've done is okay--it's not standard practice, but it's okay.
Upvotes: 2