13

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.

bdonlan
  • 224,562
  • 31
  • 268
  • 324
Pubby
  • 51,882
  • 13
  • 139
  • 180

4 Answers4

9

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.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
  • This answer is absolutely wrong! And yet managed to get 6 upvotes. SO is not working. – curiousguy May 31 '12 at 04:28
  • @DavidRodríguez-dribeas The answer does not answer the language-lawyer question, but very clearly proves something. – curiousguy Aug 14 '12 at 04:38
  • 1
    The answer is correct in that it says no this is not UB, at least. And it doesn't say anything incorrect, which makes it a stunningly good answer compared to the others here. – ech Jan 12 '17 at 18:21
7

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.

Andrew White
  • 52,720
  • 19
  • 113
  • 137
  • 2
    What do you mean by *consuming object*? – Pubby Dec 23 '11 at 02:00
  • Any object that is using the target class. If you write a class that uses string then your class is a consumer of string. – Andrew White Dec 23 '11 at 02:02
  • 3
    The more common term for "consumer" is "client". – fredoverflow Dec 23 '11 at 02:19
  • 1
    This is incorrect. The lifetime is relevant for the object itself; e.g. it has to do with how virtual functions are resolved from within a destructor. "lifetime" is a specific term in the standard with specific meaning and implications, and it does not mean that "a consuming class should not attempt to access members of an object once destruction has started". It is fine to call methods while a destructor is ongoing, *if* the class supports it. I would recommend not assuming a class supports it unless specifically documented! – ech Jan 12 '17 at 18:17
  • It's been a long time since I've looked the spec (or this answer) so you could very well be correct. Do you have a reference to your point about it being a "specific term". – Andrew White Jan 12 '17 at 21:09
  • 1
    3.8 talks about "lifetime". it refers to 12.7 which talks about what you can and can't do with an object outside of its lifetime. Do you see something there that supports this answer? (You should delete this answer, it is the top answer here but gives misleading information!) – ech Feb 26 '19 at 17:59
5

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.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 2
    Does this mean this would be invalid?: `constructor() { outside_function(this); }` (could be destructor too) – Pubby Dec 23 '11 at 02:11
  • 3
    @Pubby: You have to be very careful with what you do with `this` in a constructor and destructor, since it doesn't point to a live object. Basically, "don't use it" applies. Storing the pointer is fine, but referring to the would-be object is not. – Kerrek SB Dec 23 '11 at 02:16
  • 2
    But how can you access members without using `this` (assuming it is implicitly added)? `constructor() { this->x = 0; this->mfun(); }` – Pubby Dec 23 '11 at 02:19
  • @Pubby there are special rules when you are in the constructor, too - because the instance is not "fully alive" yet - for example, that mfun() in this->mfun() cannot be virtual. – kfmfe04 Dec 23 '11 at 02:42
  • @Pubby: inside the constructor, not all uses are invalid. For example, invoking virtual member functions may not have the intended effect, hence the "don't use it". – André Caron Dec 23 '11 at 03:02
  • 2
    @Pubby: The constructor can refer to member objects (and thus "use `this`", if you will). What the constructor mustn't do is call an external function `foo(*this)` which expects a (fully constructed) object. – Kerrek SB Dec 23 '11 at 10:16
  • @kfmfe04 "_that mfun() in this->mfun() cannot be virtual._" Wrong, virtual calls are virtual. – curiousguy Dec 24 '11 at 00:12
  • @KerrekSB Obviously, until the constructor has finished all necessary initialisations, the object cannot be used where a fully constructed object is needed. The problem you are trying to point out isn't very clear. – curiousguy Dec 24 '11 at 00:15
  • @curiousguy http://stackoverflow.com/questions/962132/calling-virtual-functions-inside-constructors – kfmfe04 Dec 24 '11 at 00:33
  • @kfmfe04 Yes, and virtual functions are virtual in constructor. – curiousguy Dec 24 '11 at 03:34
  • Some of these answers are wrong, or at least misleading. It's ok to call virtual functions from a constructor – but the behavior might not be what you expect so beware. (§ 12.7/4) It's also ok to pass `this` out to another function, and for other functions or even threads to use the object – assuming the class supports it. Be careful. And keep in mind that most objects you use might *not* support this; in particular standard library objects don't support concurrent use of an object being constructed or destroyed unless otherwise specified §17.6.4.10/2. – ech Jan 12 '17 at 18:38
2

"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.

ech
  • 118
  • 2
  • 5