Is it safe to “initialize” an object of type T with * this = T () in the constructor of T?

Is the Year () constructor 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 the year has already been initialized with int () when the threads of execution reach the constructor body. Are there any other problems?

Do not consider other cases where the same trick can cause problems.

+4
source share
3 answers

Of course, this will work and will be valid.


Explanation

All data members and databases are already built by the time you launch your ctor-body and:

[n3290: 12.7/4] Member functions , including virtual functions (10.3), can be called during construction or demolition (12.6.2). [..]

Do not confuse with:

[n3290: 12.7/1] For an object with a non-trivial constructor related to any non-static member or base class of the object before the constructor, the execution of the results starts in undefined behavior .

(NB. "Before the start of the constructor", this paragraph does not apply here.)

And there is nothing in 12.8 "Copying and moving class objects" to deny assignment at build time.


Caveat

Note that this does not mean that the object began its "lifetime":

[n3290: 3.8/1]: The lifetime of an object of type T begins when:

  • stored storage with proper alignment and size for type T and
  • If the object has non-trivial initialization, its initialization is complete.

And the last step in the "initialization" for non-delegating ctor:

[n3290: 12.6.2/10]: [..] Finally, the compound instruction of the constructor body is executed.

In general, this means that the "lifetime" object does not start until it completes the execution of its derived constructor body.

In particular, passing a pointer to an object before it begins its life is not very useful, since almost everything that calls through this pointer undefined Behavior:

[n3290: 3.5/8]: Before the life of the object begins, but after the storage that will occupy the object is allocated or, after the end of the life of the object and before storage that the occupied object is reused or freed, any pointer that refers to the storage location where the object will be or was located can be used, but only in a limited way. [..]

But:

[n3290: 3.8/3]: [..] [Note: [..] In addition, the behavior of an object under construction and destruction may not be the same as the behavior of an object whose lifetime began and did not end. 12.6.2 and 12.7 describe the behavior of objects during construction and the phases of destruction. -end note]

And, as we have already found out, 12.7 kindly informs us that members can be available at this stage of construction.


Sentence

However, your approach is hard to follow; I also had to look at the above passage before I could make sure it was valid, so it was clearly not completely intuitive.

Fortunately, C ++ 0x represents a constructor delegation so you can write:

 struct Year { Year() : Year(1970) {} Year(int y) : year(y) {} int year; }; 

(Alas, GCC 4.5.1 does not support this, so I cannot demonstrate it to you at ideone.com . In fact, for GCC as a whole, there is only a “partial patch” at the time of writing .)

+5
source

What you do works, but that would not work if you somehow call the constructor recursively ... which will cause problems. But since the constructor is called after all non-static member data of the object has been built, and the this pointer points to the actual memory that can be copied, what you did is fine - this is not standard practice, but it's fine.

+2
source

This answer is probably incorrect; see Tomalak's answer and comments. I will leave this for historical reasons, but you probably call member functions well during constructor.

Most likely no. If you have T* , say p , you can only call member functions via p-> if p points to an object. But an object is just starting its life when its constructor is finished. So, while you are in the middle of the constructor, this does not point to an object! Therefore, you certainly cannot call any member functions, such as the assignment operator for this not yet an object.

[Curiosum: In certain situations, you can say delete this; , you just need to make sure that the destructor does not refer to this in any way. You can also pass this to another location during the constructor if it is not dereferenced, just like you can pass a pointer to the garbage until you use it.]

0
source

All Articles