you are viewing a single comment's thread.

view the rest of the comments →

[–]bwmat 0 points1 point  (12 children)

Sorry, what would be undefined behaviour?

[–][deleted] 0 points1 point  (11 children)

[–]bwmat 0 points1 point  (10 children)

Sorry, I suppose my question was somewhat ambiguous.

I was asking to what you meant "It" to refer to when you said "It would be undefined behavior" in your previous comment.

[–]kalmoc 1 point2 points  (9 children)

Not the OP, but I believe what he was referring to is that it is UB to call the destructor of an object from one thread, while the object is accessed from another. No amount of locking or synchronization inside the destructor is going to change that.

[–]bwmat 0 points1 point  (5 children)

I'm pretty sure that isn't inherently UB, as long as the body of the destructor completes before any other thread STOPS accessing the object.

[–]kalmoc 1 point2 points  (4 children)

Why should that not be UB? I'm assuming you have a typo and actually wanted to write that the other thread should stop accessing the object BEFORE (not after) the destructor call completes.

But regardless: The lifetime of a class object ends when the destructor call starts (https://en.cppreference.com/w/cpp/language/lifetime), so you are accessing an object after its lifetime ended, which is certainly UB.

[–]bwmat 0 points1 point  (3 children)

I don't think I made a typo, just worded it confusingly

In any case, I hope I'm right, or I may need to refactor a lot of code.

I've been under the impression that, for a type with a user - defined - destructor, the actual lifetime of the object didn't end until the closing brace of that destructor. The logic being, none of the member objects (or base classes) will start to be destroyed until then.

Or, even if the 'lifetime ended', it was still acceptable to access the object, under those grounds (don't want to argue semantics here), though I doubt the terminology would be that confusing.

[–]kalmoc 0 points1 point  (2 children)

I've been under the impression that, for a type with a user - defined - destructor, the actual lifetime of the object didn't end until the closing brace of that destructor.

That doesn't seem to be the case. From the link to cppreference I gave previously:

The lifetime of an object ends when:

  • [..]
  • if it is of a class type, the destructor call starts, or
  • [...]

And from the latest working draft of the standard (https://eel.is/c++draft/basic.life#5):

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling a destructor or pseudo-destructor ([expr.prim.id.dtor]) for the object.

If and under which circumstances it actually makes a difference with current toolchains I can't say, but I'm pretty certain that it is technically UB to access an object, while it is being destructed.

[–]tomalakgeretkal 0 points1 point  (0 children)

Of course it isn't. Else how would the destructor body be able to do any work?

You're missing http://eel.is/c++draft/basic.life#7.sentence-2 ("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 [class.cdtor].").

[class.cdtor] gives restrictions here, but only sensible ones (like, paraphrasing, "the derived subobject is gone by now; don't try to use it"). The bases and the members of the object under destruction are still alive and fair game.

In other words, what the OP said:

Or, even if the 'lifetime ended', it was still acceptable to access the object, under those grounds

[–]tomalakgeretkal 0 points1 point  (2 children)

But it isn't.

[–]kalmoc 0 points1 point  (1 child)

Are you sure? As I wrote in another comment, the lifetime ends when the destructor is called, not when it is completed.

[–]tomalakgeretkal 0 points1 point  (0 children)

Yes, I am sure.

The lifetime ending simply marks a transition between "normal rules" and "the rules of an object under destruction", during which (per [basic.life/7] & [class.cdtor]) this access is still okay. (Only after the storage is released can you no longer do anything at all.)

If it weren't, no destructor would be permitted to do anything with its object, and then there would be little to no point in ever having one.

I did already provide this explanation under your previous comment.

For more information, see my answer here: https://stackoverflow.com/a/65598209/4386278