Question

Is it safe to move object inside its destructor

I'm 99% sure the answer to my question is 'Yes'. I just want to double check my assumption is right and I want to be sure that there is nothing in the upcoming C++ standards that could change the rules (like destructive move if it is really possible).

So, my case is as following. I have an object of the Request type whose lifetime is managed by std::shared_ptr<Request>. When the object is about to die (i.e. the ref counter is zero and std::shared_ptr is calling the ~Request destructor) I need to check some condition and create another instance of the Request type with exactly the same data. Basically I just need to prolong the subscription.

The cheapest way from my point of view is just to call the move ctor of the Request class:

Request::~Request()
{
  if(condition)
  {
    service.subscribe(std::make_shared<Request>(std::move(*this)));
  }
}

As far as I know all data members of the Request instance in the context of destructor are still alive. They are not destroyed yet. So it has to be safe to move them somewhere, right? Is my assumption in line with the idea of C++ and I'm not doing anything stupid?

Related questions:

 6  265  6
1 Jan 1970

Solution

 1

In the end, the line service.subscribe(std::make_shared<Request>(std::move(*this))); might be legal because:

The lifetime of an object o of type T ends when:
(1.3) if T is a non-class type, the object is destroyed, or
(1.4) if T is a class type, the destructor call starts, or
(1.5) the storage which the object occupies is released, or is reused by an object that is not nested within o

I emphazised the relevant line.
https://timsong-cpp.github.io/cppwp/n4861/basic.life#1.4

Yet, a few lines later:

6 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 pointer that represents the address of 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 [class.cdtor].

https://timsong-cpp.github.io/cppwp/n4861/basic.life#6

(Again emphasize is mine)

Following [class.cdtor] link:

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.

https://timsong-cpp.github.io/cppwp/n4861/class.cdtor#1

A contrario, we may understand that other usage are legal (otherwise, as stated by @interjay in comment, destructors would be effectively useless).

From the snippet, its not possible to tell if there are no other issues (see the question comments).

2024-07-25
Oersted

Solution

 0

The short answer is Yes. Destruction of the object and freeing of the object memory occurs only after the destructor exits cleanly.

However, I would use an object-local Mutex in the destructor to ensure that the same destructor doesn’t get called twice, if that is allowed by the compiler. I believe later C++ versions don’t allow concurrent destruction, but some earlier versions did.

Operations inside a destructor should be read-only on the object, to ensure not to violate any access rules set on members prior to the destructor being called.

Copying the object itself should be okay, as long as member functions aren’t called that may violate the read-only rule.

2024-07-25
Randy Dryburgh

Solution

 0

I think it’s OK if you sure that no exceptions will appear or use try/catch(…)

2024-07-25
Kirill Lanskoy