Lifetime of Object Is Over Before Destructor Is Called

Lifetime of object is over before destructor is called?

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.

Clarification about object lifetime in destructor

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.

C++ destructor called before lifetime of scope

Word curr_word = *curr_word_ptr; defines a local Word, that only lives in the local scope, your function. When the function exits, it is destroyed. Note it is a copy of the initial Word that is destroyed, not the original.

If you want handy syntax so you don't have to dereference all over, or make a copy, use a reference:

Word &word = *curr_word_ptr;

This is the syntactic sugar C++ provides to refer to an object without pointers (directly). Note though, any changes made to word will affect your original word as well in this case.

The problem is even worse if your Words contains dynamically allocated memory. Assuming you use the default copy constructor, the addresses will be copied. As such, destruction of a local Word will free memory still referenced by the original Word, causing a crash when next accessed.

At which point of destructor call the object ceases to exist?

At which point of destructor call the object ceases to exist?

The lifetime of the object is ended by the call to its destructor. Within the destructor body, the sub-objects are still alive and member functions may be called. After the destructor body, the sub objects are destroyed.

if it's legal to call an object's function inside its destructor or not

It is legal.

Note however that calling a virtual function works differently than one might expect.

is Destructor really destroy memory or just runs before the lifetime of object is going to end?

or just runs before the lifetime of object is going to end?

To be clear: The lifetime of the object ending and the calling of the destructor happen in the same point in time, not one after the other.

is destructor de-allocate there memory ?

Not necessarily. See following example for details.


  1. if destructor do not de-allocate memory then what actually it does ?

Let's consider following class:

struct example : base {
another_class member;
~example() {
// destructor body
}
};

The destructor of example first executes the "destructor body", then it executes the destructors of all sub objects (which consists of member and base in this example). If the body, or the destructor of any sub object deallocates some memory, then that's what the destructor does. But the memory of the object being destroyed is generally not deallocated by the destructor.

Indeed, delete does two things: Call the destructor, and dealloate the storage.

what's about if I call destructor manually for these dynamic objects with help of pointer p->~destructor()(where p is ptr pointing to these dynamic memory)

That destroys the object.

it will destroy memory or not ?

The storage is not deallocated by an explicit call to a destructor.

then what's about if I call destructor manually for this local object a. ~destructor (where a is local object) it will destroy memory or not ?

The storage is not deallocated by an explicit call to a destructor regardless of where the object is stored.

if not while scope is going to end destructor invokes, then it not goes into UB right.

If a destroyed object in automatic storage goes out of scope, then the behaviour of the program is undefined.

Why We Say Destructor Call When Object Goes out of Scope?

An object which goes out of scope has its destructor called. That is an unchangeable guarantee which is mandated by the C++ language standard. It doesn't matter if you've manually called the destructor beforehand; when it goes out of scope, the destructor will be called. If you've written your destructor such that bad things happen if it's called twice, or if the extra behavior which the compiler inserts into the destructor code doesn't want to be called twice, bad things will happen.

This is one of many reasons why you should never manually call a destructor.

Ending lifetime of STL container without calling the destructor

I've asked this question here: https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/R_KPazXbE0k

According to 17.5.2.3 / 1:

Clauses 18 through 30 and Annex D do not specify the representation of classes, and intentionally omit
specification of class members (9.2). An implementation may define static or non-static class members, or
both, as needed to implement the semantics of the member functions specified in Clauses 18 through 30 and
Annex D.

In other words, implementation may have some private members which use resources other than memory. Thus, there is no guarantee that there are no other side effects (at least in the current C++11 Standard).

Legality of using delete-expression on a pointer to an object of class type with a trivial destructor/scalar type whose lifetime has ended

It seems that there is a wording defect. Either your code is intended to be legal, or it's not. If it is intended to be legal, then [basic.life]/6.2 should have an exception for a trivial destructor. If it's not intended to be legal, then the words "with a non-trivial destructor" should be struck from [basic.life]/6.1 because even if the destructor is trivial, the inevitable destructor call will violate p6.2.

I suspect that it was intended to be legal, because there's no point in preserving the explicit exception in the case of delete if not to prevent breaking code that was, in fact, calling delete on objects with trivial destructors that are outside their lifetimes.

N2762 removed the trivial destructor exception for all the other UB-causing operations on pointers to objects outside their lifetimes, but conspicuously kept it for delete-expressions. This suggests that there was a need to keep this exception in the language in order to avoid breaking code.

Most likely the reason why the second bullet was not also changed to make an exception for a trivial destructor call is that the authors forgot that a delete-expression does call the destructor even if it's trivial. They might have assumed that delete was specified to skip the destructor call if it would be trivial.

(Note also that in C++98 through C++17, your S object's lifetime is not ended by the destructor call anyway because [basic.life]/1 specified that a destructor call ends the lifetime of the object only if it is non-trivial; this was changed in C++20 by CWG2256. However, due to N2762, in C++11 and later, if an object's lifetime has not yet started because it has nontrivial initialization, we can run into an issue that is similar to the one described by the OP.)

I think it's worth filing a defect report about this, though I'm not sure what the outcome will be. So much time has elapsed since N2762 that I would imagine the committee would actually want to consider whether the exception for trivial destructors ought to be eliminated at this point (i.e., fixing p6.1 instead of p6.2); after all, the resolution of CWG2256 may also have broken some code, but it was probably code of the sort that has become increasingly rare over the years since C++ diverged from C.



Related Topics



Leave a reply



Submit