kessler bebe
kessler bebe

Reputation: 106

When is the destructor of an object that is being moved to called in C++?

I have some class A, which I can either construct using nothing, or an std::function. On destruction that given function should be called (in case there is one). My problem is that the object gets destroyed right after it is created and returned by my getSomeA() function which calls the std::function before it is supposed to be called. The function passed to the constructor should only be called once. Some example code:

#include <iostream>
#include <functional>

static void testFunction(const std::string& msg)
{
    std::cout << "TestFunction: " << msg << "\n";
}

class A {
public:
    A(void) = default;

    A(const std::function<void()>& onDestroy) :
        onDestroy(onDestroy)
    {  }

    ~A(void)
    {
        if (onDestroy) onDestroy();
        else std::cout << "in dtor but no onDestroy was set\n";
    }

private:
    std::function<void()> onDestroy;
};

A getSomeA(void)
{
    return A(std::bind(testFunction, "the A that was created inside getSomeA"));
}

int main(void)
{
    A b1;
    std::cout << "After creating b1\n";
    b1 = getSomeA();
    std::cout << "After reassigning b1\n";

    std::cout << "Here the program works with b1...\n";
}

The program outputs

After creating b1
TestFunction: the A that was created inside getSomeA
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA

So the function is called before it is supposed to be called (at the end of int main()).

After adding a move constructor and assignment operator everything works as expected:

A(A&& other) :
        onDestroy(std::exchange(other.onDestroy, nullptr))
    {  }

    A& operator=(A&& other)
    {
        onDestroy = std::exchange(other.onDestroy, nullptr);
        return *this;
    }

And the program outputs

After creating b1
in dtor but no onDestroy was set
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA

The actual question: Where is the object destroyed for the first time so that testFunction is called? In getSomeA() or in the main function before the assignment but after the object was created in getSomeA()?

All the edits: I tried to bring down my question for one hour but since I have no idea about move/copy semantics in C++ that was pretty hard for me.

Upvotes: 1

Views: 239

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118292

In the first version the object gets destroyed for the first time as part of returning the object constructed in getSomeA. Its return statement effectively constructs a temporary object, which then gets assigned to main's b1. If you ignore the process of returning from a function, the sequence of events is:

A <temporary object>(std::bind( ... )

b1=<temporary object>

<temporary object gets destroyed>

At this point the bound function gets called, as a result of the temporary object gets destroyed. The temporary object is a fully tricked out object, with all the rights and privileged granted thereof. Including a destructor.

But wait, there's more! b1 is a perfect bit-by-bit copy of the original object, with the bound function, before it got destroyed. So when b1 gets destroyed, the function gets called again.

This is the indirect consequence of the Rule Of Three. When an object owns a resource, and must maintain an exclusive ownership of the resource you will need to provide a copy and/or move constructor and and assignment operator to spell out exactly what should happen in that situation.

P.S. these rules change slightly with C++17's guaranteed copy elision, but the underlying concept is still the same.

Upvotes: 1

Related Questions