C ++ Assigning an object with a dedicated stack and calling the destructor

I am trying to figure out what seems to be some weird behavior when assigning a new value to an object allocated on the stack (the destructor is called twice for the same dataset). I'll just start with a piece of code and its output:

    class Foo {
    public:
        Foo(const string& name) : m_name(name) {
            log("constructor");
        }
        ~Foo() {
            log("destructor");
        }
        void hello() {
            log("hello");
        }
    private:
        string m_name;
        void log(const string& msg) {
            cout << "Foo." << this << " [" << m_name << "] " << msg << endl;
        }
    };

    int main() {

        {
            Foo f {"f1"};
            f.hello();

            f = Foo {"f2"};
            f.hello();
        }
        cout << "scope end" << endl;
    }

      

Output:

    Foo.0x7fff58c66a58 [f1] constructor
    Foo.0x7fff58c66a58 [f1] hello
    Foo.0x7fff58c66a18 [f2] constructor
    Foo.0x7fff58c66a18 [f2] destructor
    Foo.0x7fff58c66a58 [f2] hello
    Foo.0x7fff58c66a58 [f2] destructor
    scope end

      

What I expected to see:

  • 0x ... 58 is created / initialized on the stack
  • 0x ... 18 is created / initialized on the stack
  • Foo destructor is called at 0x ... 58 (with data f1)
  • Foo destructor is called on 0x ... 18 (with data f2)

What actually happens:

  • 0x ... 58 is created / initialized on the stack
  • 0x ... 18 is created / initialized on the stack
  • data from 0x ... 18 (f2) is copied to 0x ... 58
  • Foo destructor is called on 0x ... 18 (with data f2)
  • Foo destructor is called on 0x ... 58 (also with data f2)

So in the end, Foo destructor is called twice for the same data (f2) . Clearly I missed something about how this works internally, so can someone point me in the right direction?

+3


source to share


2 answers


Your f instance is assigned a copy of Foo {"f2"}, this is not a new construct.

Add the following = operator to illustrate what is actually happening.



Foo& Foo::operator=(const Foo& other) {
    cout << "Foo::operator=(const Foo& other)" << endl;
    m_name = other.m_name;  
    return *this;
}

      

+4


source


Before creating the second object Foo

, you only have one object at the address 0x..58

.

Address: 0x..58            Data: { m_name "f1" }
Address: 0x..18            Data: unknown

      

The line f = Foo {"f2"};

first creates a new Foo object whose value m_name

is "f2"

, and stores it at the address 0x..18

. Then it assigns that object to a variable f

.



This assignment does not destroy the preexisting object in f

, it only copies data items into it. Since Foo objects only have one data item m_name

, the assignment simply copies the second object m_name

into the first.

Address: 0x..58            Data: { m_name "f2" }
Address: 0x..18            Data: { m_name "f2" }

      

The destructors are then called for each of these objects. Inference does not mean that the same object is destroyed twice, it just means that both objects have the same m_name

.

+3


source







All Articles