30

[class.dtor]/15 reads, emphasis mine:

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8).

However, as far as I can tell, this is the only reference in the standard to an object "existing." This also seems to contrast with [basic.life], which is more specific:

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.

We have two different wordings here: "the lifetime of an object ends" and "the object no longer exists," the former only happens with a non-trivial destructor and the latter happens with any destructor. What is the significance of the difference? What is the implication of an object no longer existing?

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    C++03 has the same wording. Makes me wonder if it's just shoddiness that needs some cleanup. – T.C. May 19 '15 at 01:59
  • I think these are just synonyms but will wait and see if someone who knows the standard better than I do pipes in... – Billy ONeal May 19 '15 at 01:59
  • 10
    http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1285 – T.C. May 19 '15 at 01:59
  • Seems to me that the current wording of the Standard allows post-trivial-destruction use of objects until memory reuse/release, as I've illustrated in this program on [ideone.com](http://ideone.com/8HRCSd). – Tony Delroy May 19 '15 at 02:58
  • 2
    @Tony: Lots of things work on GCC (which ideone is using) that are not standard; working there isn't really evidence that the standard says anything in particular. (The biggest thing I can think of being GCC's support for C99 style VLAs) – Billy ONeal May 19 '15 at 04:24
  • @BillyONeal: I didn't say GCC/ideone were evidence of anything; rather, it's my current understanding of the C++11 Standard that the the code I list there is *required* by the C++11 Standard to work with well-defined behaviour on any C++11 compiler. I believe that code illustrates the requirement for a curious "post-existence lifetime" for trivially destructible objects. That it also happens to ostensibly "work" there is a bonus of doubtful import, as you say. – Tony Delroy May 19 '15 at 05:49
  • 1
    @TonyD: `int` is not a class type. This means the lifetime is defined by the "storage which the object occupies is reused or released." clause. Your first definition from `[class.dtor]/15` applies to class types. – MSalters May 19 '15 at 08:08
  • @MSalters: ah solid point - I'd skipped over the "[class.dtor]" in Barry's question. Example updated accordingly [here](http://ideone.com/YloIdw). Cheers. – Tony Delroy May 19 '15 at 08:19
  • 2
    "exist" presumably has something to do with lifetime beginning which is [also unclear](http://stackoverflow.com/questions/30114397/constructing-a-trivially-copyable-object-with-memcpy) – M.M May 20 '15 at 03:04
  • @TonyD In your example you probably want `n` to have type `unsigned char`, as reading an indeterminate value (under the premise that an object appeared out of thin air, as you are trying to illustrate) is otherwise UB. Similar examples sidestep the issue by assigning, rather than reading, which still illustrates the problem of what, exactly, is being assigned to. – Luc Danton May 24 '15 at 02:27
  • @LucDanton: "an object appeared out of thin air, as you are trying to illustrate" - I wasn't - seem to me that the original object is still there in some manner, and I've no particular reason to think that the earlier initialisation doesn't suffice (as least no more than is evident from the comment in the code). But, your point's certainly interesting for questioning the object state... not denying you might be right... but it does seem to me that the Standard's vague enough only an idiot would bet on any particular compiler writer's interpretation/implementation, so ultimately - who cares. – Tony Delroy May 24 '15 at 16:32
  • @T.C. The wording exists since C++98. Assuredly 15 was written before the notion of lifetime was precisely defined. – Columbo Jul 24 '15 at 08:15
  • Can everyone please move their comments to answers? – onebree Jul 24 '15 at 14:52
  • 1
    @MattMcNabb +1, and in a constructor's initializer list, it's very easy to access members' storage before their constructor is called, another example of "existence starts before lifetime begins". – user3528438 Jul 28 '15 at 19:10

1 Answers1

1

The quoted wording would seem to imply that a compiler could correctly insert code that returns the memory associated with an object to the heap at the beginning of its destructor. But doing that would eliminate the ability of an object to reference its own members during destruction, which is required if an object is to be able to destroy itself.

So I think the quoted wording is broken and should be fixed.

Concerning what "lifetime" and "existence" mean, I propose that there are some different contexts, in which they mean different things:

Within the context of construction, lifetime and existence begin when a constructor begins. Outside that context, they begin when a constructor ends.

Within the context of destruction, lifetime and existence end when a destructor ends. Outside that context, they end when destruction begins.

So an object may refer to its own members during construction, and potentially pass itself to functions of other objects, which may refer to the object and its members, and so on. But in general, objects (instances of classes) may not be referenced (without producing undefined behavior) until after one of their constructors has finished.

And an object's destructor may refer to its own members and call functions of other (existing) objects, which may refer to the object being destroyed and/or its members. But in general, an object may not be referenced after its destructor has started.

This sort of multi-contextual definition is what makes the most sense to me, but I can see arguments being made that an object should be considered to be alive from the moment memory is allocated for it to the moment that memory is released, and I would say memory for a shallow copy should be allocated for an object when one of its constructors starts, and released when its destructor ends.

Shavais
  • 2,476
  • 1
  • 27
  • 25
  • Yeah, I'm not sure what addled part of my brain that left field aside came from. But hopefully the rest of the answer is more-or-less valid. – Shavais Jul 27 '15 at 18:13
  • I don't see how you draw the conclusion that the wording allows memory to be freed before the destructor is finished. Just because the object itself has ended its lifetime, doesn't say anything about the lifetime of its members; those members aren't destroyed until the *end* of the destructor. – Mark Ransom Jul 27 '15 at 18:31
  • Well, if the object "doesn't exist" anymore, doesn't that kind of imply that the memory for a shallow copy of it can be freed? If the object doesn't exist within its destructor, then you can't say delete this->myMember from within that destructor. – Shavais Jul 27 '15 at 19:31
  • "_But in general, an object may not be referenced after its destructor has started._" I don't understand what you are trying to say. Until a destructor has reached `}` an object is fully usable, as everybody knows. – curiousguy Aug 02 '15 at 03:14
  • I'm trying to interpret the standard. It definitely seems to be trying to say that, for example, you can't call the destructor once the destructor has started. (Or, well, doing so may produce "undefined behavior.") My guess would be that if a compiler truly implemented the standard, you wouldn't be able to do anything else with the object either, outside of the context of the destructor call, but perhaps I'm wrong. – Shavais Aug 03 '15 at 15:46
  • @curiousguy: Until the destructor reaches `}`, pointers derived from the value of `this` within that destructor may be used to access the object, but that doesn't imply that the object can be derived using lvalues not derived from that pointer. I don't know if the Standard is making that distinction, but I can see how it could make sense. – supercat Dec 16 '16 at 23:23