Another question cites the C++ standard:
3.8/1 "The lifetime of an object of type T ends when: — if T is a class type with a non-trivial destructor (12.4), the destructor call
starts, or — the storage which the object occupies is reused or
released."
It would seem that this means accessing members of an object from a destructor is not allowed. However this seems to be wrong, and the truth is something more like what's explained in Kerrek SB's answer:
Member objects come alive before a constructor body runs, and they
stay alive until after the destructor finishes. Therefore, you can
refer to member objects in the constructor and the destructor.
The object itself doesn't come alive until after its own constructor
finishes, and it dies as soon as its destructor starts execution. But
that's only as far as the outside world is concerned. Constructors and
destructors may still refer to member objects.
I'm wondering if in the destructor I can pass the object's address to an outside class, like:
struct Person;
struct Organizer
{
static void removeFromGuestList(const Person& person); // This then accesses Person members
}
struct Person
{
~Person() {
// I'm about to die, I won't make it to the party
Organizer::removeFromGuestList(*this);
}
};
This seems OK to me as I think an object's lifetime lasts until after the destructor finishes, however this part of the above answer has me doubting:
The object itself doesn't come alive until after its own constructor
finishes, and it dies as soon as its destructor starts execution. But
that's only as far as the outside world is concerned. Constructors and
destructors may still refer to member objects.
The C++ Standard does seem to be just a little bit self-contradictory regarding the exact status of class members during execution of the destructor.
However, the following excerpt from this Draft C++ Standard may give some reassurance that your call to the removeFromGuestList function should be safe (bold italics formatting added by me):
15.7 Construction and destruction
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. For an object with a non-trivial destructor,
referring to any non-static member or base class of the object after
the destructor finishes execution results in undefined behavior.
What remains unclear (at least, to me) is whether or not referring to those class members via a reference to the object being destroyed is valid once the destructor has started execution. That is, assuming your Person class has a member, ObjectType a, is referring to person.a in your removeFromGuestList function valid?
On the other hand, rather than passing *this as its argument, if you were to pass each required member as a 'distinct object', then you would be safe; so, redefining that function as, say, removeFromGuestList(const ObjectType& a) (with possible additional arguments) would be completely safe.
Related
in C++, when the object's desctructor is called, it first invokes child class's destructor, and then parent's, which is the opposite of construct procedure.
But why? It seems to be a simple question, but I haven't found a satisfying answer on the internet. Could someone explain the nessisity of doing destructing in such sequence?
Since this was tagged [language-lawyer], this is the rule that says what a destructor does:
[class.dtor]
After executing the body of the destructor and destroying any objects with automatic storage duration allocated within the body, a destructor for class X calls the destructors for X's direct non-variant non-static data members, the destructors for X's non-virtual direct base classes and, if X is the most derived class ([class.base.init]), its destructor calls the destructors for X's virtual base classes.
All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes.
Bases and members are destroyed in the reverse order of the completion of their constructor (see [class.base.init]).
Why?... It just makes sense. Things that are constructed in one order are generally destroyed in the opposite order. This convention applies to sub objects of classes, as well as elements of arrays, local variables in a function as well as objects with static storage duration destroyed at the end of the program. I cannot think of anything where this isn't the case.
Although dependencies between objects within their lifetime can be two-directional, during the construction and destruction the dependency can only be in one direction. Object that is created before cannot depend - within its constructor - on an object that is created later (because that object doesn't exist yet). Same applies to destruction but in reverse: An object that is destroyed later cannot depend - within its destructor - on an object destroyed before (because that object doesn't exist anymore).
If you can depend on something within your construction, then you will typically expect to be able to depend on that something within the destruction. In other words, you would expect the direction of dependency to remain in the same direction. The inverse destruction order satisfies this expectation.
To return to the c/d-tors, constructor body is the last thing to execute in the constructor, so the destructor body should be the first thing to execute in the destructor. And it will be useful in some cases to be able to use the base sub object within destructor body, which wouldn't be possible if it had already been destroyed.
Why does the base object need to exsit in a valid state in destructing procedure?
To understand this, it should help to think about why the destructor body exists in the first place. Typically, it is to change the internal state of the class in preparation for ending the lifetime. A typically familiar action is deletion of an owning pointer stored as a member (this is just an example: use smart pointers instead). If the object no longer exists in a valid state, then it would be too late to touch that now-invalid state.
but any base class function could be virtual function, which could also access child member in destructor procedure.
Virtual function calls resolve to the current class during destruction (just like during construction).
Assuming you're talking about parent/child meaning inheritance consider that
struct Car : Vehicle { ... };
is not really much different than
struct Car { Vehicle _base; ... };
except that automatically when you refer to a Vehicle property in a Car method _base. is implicitly added by the compiler.
The standard even calls this the "base class sub-object"... it's an object that has no name and that you use implicitly, but it's still there.
Now in C++ members of a class are constructed before the class itself, and destroyed after. The same happens to the implicit "base class sub-object". So when building a car you need first to build the vehicle... and after destroying the car all individual members are destroyed, including the vehicle.
During my studing exeption's mechanism I found that there are calls of destructors for fields of the object while stack's unwinding. Let me explain explicitly:
class X
{
File_ptr aa;
Lock_ptr bb;
public:
X(const char* x,const char* y):aa(x),bb(y){}
//.......
}
So,now if Lock_ptr's constructor throws an exeption, object aa will be destroyed;
The question is "why"? I always thought that fileds of the object are not usual automatic (lochal) objects.They are created before constructor initializes them.So they can't be destryed after they're out of scope of constructor (Otherwise they would be destroyed as soon as constructor's finished its work)
Subobjects (including non-static data members) have the same storage duration as the complete objects to which they belong. This is not the same as saying that they are automatic. An automatic object is destroyed at the end of a block. A subobject is destroyed whenever its complete object is destroyed. For example, if the complete object is created with new and destroyed with delete (i.e. has dynamic storage duration), then the subobject is also created in the call to new, and destroyed in the call to delete. On the other hand, a subobject of an automatic object is also automatic.
If the constructor for X::bb throws an exception, then it means the complete object of type X cannot be constructed. All subobjects that have already been constructed, such as X::aa, must be destroyed, because a subobject, having the same storage duration as its complete object, cannot survive without the complete object.
On the other hand, if construction of the entire X object completes successfully, X::aa and other subobjects won't be destroyed until (shortly after) the complete X object is destroyed.
The construction and destruction rules for C++ are intended to guarantee that, as long as a program terminates normally, every object that is created is also destroyed exactly once. This is essential for the RAII idiom. In this example, if X::aa acquires resources when it is constructed, the language must ensure that those resources will be released. If X::aa's destructor is not called when construction of the X fails, then when should it be called?
X has a "real" constructor that constructs aa and bb, and then after that the constructor body of X is called. This is why the initializer list is before X's constructor "body". Inside of this "real" constructor, the bases and then members are created as if they were on the stack in the order they're declared in the class, including for stack unwinding. I even have a picture:
Destructors work on a vaguely similar principle, except in reverse, but can be even more complicated if the destructor is virtual. If the destructor is virtual, then there's three parts. There's a "stub" destructor that gets called when someone calls the destructor, which dispatches to the most-derived type's "real" destructor. The "real" destructor calls your destructor "body", and then destructs the members in the reverse order that they're declared in the class, and then it destructs the base classes (still in reverse order, same as a stack).
*QuestionC correctly observes that static members are completely independent of everything I wrote here.
Member objects (unless they are static) are constructed when the class constructor is called. The behavior you are seeing is normal and correct.
Member objects are not destroyed when the constructor is finished. They are destroyed when the class destructor is called (in reverse order of construction).
Suppose I have a class whose constructor spawns a thread that deletes the object:
class foo {
public:
foo()
: // initialize other data-members
, t(std::bind(&foo::self_destruct, this))
{}
private:
// other data-members
std::thread t;
// no more data-members declared after this
void self_destruct() {
// do some work, possibly involving other data-members
delete this;
}
};
The problem here is that the destructor might get invoked before the constructor has finished. Is this legal in this case? Since t is declared (and thus initialized) last, and there is no code in the constructor body, and I never intend to subclass this class, I assume that the object has been completely initialized when self_destruct is called. Is this assumption correct?
I know that the statement delete this; is legal in member-functions if this is not used after that statement. But constructors are special in several ways, so I am not sure if this works.
Also, if it is illegal, I am not sure how to work around it, other spawning the thread in a special initialization-function that must be called after construction of the object, which I really would like to avoid.
P.S.: I am looking for an answer for C++03 (I am restricted to an older compiler for this project). The std::thread in the example is just for illustration-purposes.
Firstly, we see that an object of type foo has non-trivial initialization because its constructor is non-trivial (§3.8/1):
An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor.
Now we see that an object of type foo's lifetime begins after the constructor ends (§3.8/1):
The lifetime of an object of type T 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.
Now, it is undefined behaviour if you do delete on the object before the end of the constructor if the type foo has a non-trivial destructor (§3.8/5):
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated [...] any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, [...]
So since our object is under construction, we take a look at §12.7:
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2).
That means that it's fine for self_destruct to be called while the object is being constructed. However, this section says nothing specifically about destroying an object while it is being constructed. So I suggest we look at the operation of the delete-expression.
First, it "will invoke the destructor (if any) for the object [...] being deleted." The destructor is a special case of member function, so it is fine to call it. However, §12.4 Destructors says nothing about whether it is well-defined when the destructor is called during construction. No luck here.
Second, "the delete-expression will call a deallocation function" and "the deallocation function shall deallocate the storage referenced by the pointer". Once again, nothing is said about doing this to storage that is currently being used be an object under construction.
So I argue that this is undefined behaviour by the fact that the standard hasn't defined it very precisely.
Just to note: the lifetime of an object of type foo ends when the destructor call starts, because it has a non-trivial destructor. So if delete this; occurs before the end of the object's construction, its lifetime ends before it starts. This is playing with fire.
I daresay it is well-defined to be illegal (though it might obviously still work with some compilers).
This is somewhat the same situation as "destructor not called when exception is thrown from constructor".
A delete-expression, according to the standard, destroys a most derived object (1.8) or array created by a new-expression (5.3.2). Before the end of the constructor, an object is not a most derived object, but an object of its direct ancestor's type.
Your class foo has no base class, so there is no ancestor, this therefore has no type and your object is not really an object at all at the time delete is called. But even if there was a base class, the object would be a not-most-derived object (still rendering it illegal), and the wrong constructor would be called.
Formally the object doesn't exist until the constructor has finished successfully. Part of the reason is that the constructor might be called from a derived class' constructor. In that case you certainly don't want to destroy the constructed sub-object via an explicit destructor call, and even less invoke UB by calling delete this on a (part of a) not completely constructed object.
Standardese about the object existence, emphasis added:
C++11 §3.8/1:
The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization
if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial
default constructor. [Note: initialization by a trivial copy/move constructor is non-trivial initialization. —end note ] The lifetime of an object of type T 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.
The constructor in this case is non-trivial just by being user-provided.
delete this; works correctly in practice on most platforms; some may even guarantee correct behavior as a platform-specific extension. But IIRC it isn't well-defined according to the Standard.
The behavior you're relying on is that it's often possible to call a non-virtual non-static member function on a dead object, as long as that member function doesn't actually access this. But this behavior is not allowed by the Standard; it is at best non-portable.
Section 3.8p6 of the Standard makes it undefined behavior if an object isn't live during a call to a non-static member function:
Similarly, 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 glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated
storage, and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if:
an lvalue-to-rvalue conversion is applied to such a glvalue,
the glvalue is used to access a non-static data member or call a non-static member function of the object, or
the glvalue is implicitly converted to a reference to a base class type, or
the glvalue is used as the operand of a static_cast except when the conversion is ultimately
to cvchar& or cvunsigned char&, or
the glvalue is used as the operand of a dynamic_cast or as the operand of typeid.
For this specific case (deleting an object under construction), we find in section 5.3.5p2:
... In the first alternative (delete object), the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject representing a base class of such an object (Clause 10). If not, the behavior is undefined. In the second alternative (delete array), the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression. If not, the behavior is undefined.
This requirement is not met. *this is not an object created, past tense, by a new-expression. It is an object being created (present progressive). And this interpretation is supported by the array case, where the pointer must be the result of a previous new-expression... but the new-expression is not yet completely evaluated; it is not previous and it has no result yet.
I don't understand this:
3.8/1 "The lifetime of an object of type T ends when: — if T is a class type with a non-trivial destructor (12.4), the destructor call
starts, or — the storage which the object occupies is reused or
released."
If the lifetime ends before the destructor starts, doesn't that mean accessing members in the destructor is undefined behavior?
I saw this quote too:
12.7 "For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor
finishes execution results in undefined behavior."
But it doesn't make clear what's allowed during the destructor.
If the lifetime ends before the destructor starts, doesn't that mean accessing members in the destructor is undefined behavior?
Hopefully not:
From N3242 Construction and destruction [class.cdtor] /3
To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
The "lifetime" of an object is relevant for consumers of the object, not the object itself. Therefore a consuming class should not attempt to access members of an object once destruction has started.
No, there's no problem:
Member objects come alive before a constructor body runs, and they stay alive until after the destructor finishes. Therefore, you can refer to member objects in the constructor and the destructor.
The object itself doesn't come alive until after its own constructor finishes, and it dies as soon as its destructor starts execution. But that's only as far as the outside world is concerned. Constructors and destructors may still refer to member objects.
"Lifetime" doesn't mean that. It is a precisely defined term in the standard that has a variety of implications, but it might not have all the implications that you would think. Members can still be used during construction and destruction, outside code can call member functions, etc, etc.
Granted, it's a bit odd for client code to call member functions concurrently with the destructor, but not unheard of and certainly not disallowed by the language. In particular, std::condition_variable explicitly allows the destructor to be invoked while there are outstanding calls to condition_variable::wait(). It only prohibits new calls to wait() after the destructor starts.
Herb Sutter mentions in one of his http://www.gotw.ca articles that an object is constructed(has valid existence) only if the constructor executes completes.ie to put it in a crude way control passes beyond its final brace.
Now consider the following code
class A
{
public:
A()
{
f();
}
void f()
{
cout << "hello, world";
}
};
int main()
{
A a;
}
Now from what Herb says, can't we say that since A is not completely constructed inside its constructor Calling f() inside the constructor is invalid as the "this" ptr is not ready yet.
Still there is indeed a valid "this" inside the constructor and f() does get called.
I don't think Herb is saying something incorrect... but guess i am interpreting it incorrectly....can some explain to me what exactly that is?
Here is the link to the article : http://www.gotw.ca/gotw/066.htm
It talks about exceptions from constructors. Specifically here is the extract from it on which my question is based:
-When does an object's lifetime begin?
When its constructor completes successfully and returns normally. That is, control reaches the end of the constructor body or an earlier return statement.
-When does an object's lifetime end?
When its destructor begins. That is, control reaches the beginning of the destructor body.
Important point here is that the state of the object before its lifetime begins is exactly the same as after its lifetime ends -- there is no object, period. This observation brings us to the key question:
We might summarize the C++ constructor model as follows:
Either:
(a) The constructor returns normally by reaching its end or a return statement, and the object exists.
Or:
(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed.
Now from what Herb says, can't we say
that since A is not completely
constructed inside its constructor
Calling f() inside the constructor is
invalid as the "this" ptr is not ready
yet.
That is only when f() is a virtual method of class A or its inheritance hierarchy and you expect the runtime resolution for f() according to the right object. In simple words, virtual mechanism doesn't kick in if the method is invoked inside constructor.
If f() is not a virtual function, there is no harm in calling it from constructor(s) provided you know what exactly f() does. Programmers usually call class methods like initialize() from constructor(s).
Can you give me the link to the Herb Sutter's article?
By the time program flow enters your constructor, the object's memory has been allocated and the this pointer is indeed valid.
What Herb means, is that the object's state may not have entirely initialized. In particular, if you are constructing a class derived from A, then that class' constructor will not have been called while you are still inside A's constructor.
This is important if you have virtual member functions, since any virtual function in the derived class will not be run if called from within A's constructor.
Note: it would have been easier with the exact article, so that we could have some context
Lifetime considerations are actually pretty complicated.
Considering the constructor of an object, there are two different point of views:
external: ie the user of an object
internal: ie, you when writing constructors and destructors (notably)
From the external point of view, the lifetime of an object:
begins once the constructor successfully completed
ends when the destructor begins to run
It means that if you attempt to access an object mid-construction or mid-destruction Bad Things Happen (tm). This is mostly relevant to multi-threaded programs, but may happen if you pass pointers to your object to base classes... which leads to...
...the internal point of view. It's more complicated. One thing you are sure of is that the required memory has been allocated, however parts of the objects may not be fully initialized yet (after all, you are constructing it).
in the body of the constructor, you can use the attributes and bases of the class (they are initialized), and call functions normally (virtual calls should be avoided).
if it's a base class, the derived object is not initialized yet (thus the restriction on virtual calls)
The implication from the lifetime not having started yet is mainly that, should the constructor throw an exception, the destructor will not be run.
Beware of member variables that are not yet initialized. Beware of virtual functions: the function that you call might not be the one that you expect if the function is virtual and a derived object is created. Other than that, I do not see any problem calling methods from the constructor. Especially the memory for the object has already been allocated.