Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning a dereferenced shared_ptr

Consider the following class:

struct MyClass {
    int mId;
    MyClass(int id): mId(id) {}
   ~MyClass() { std::cout << "deleting: " << mId << std::endl; }
};

And the usage:

std::shared_ptr<MyClass> p(new MyClass(0));
MyClass& m = *p;
m = MyClass(2);

The result is:

deleting: 2
deleting: 2

Please help me understanding:

  1. Why there are two MyClass(2) objects (assumption made on the destructor logs)
  2. Is this a memory leak? Shouldn't the MyClass(0) leak?

Thank you.

like image 473
Zaur Nasibov Avatar asked Apr 13 '26 10:04

Zaur Nasibov


2 Answers

There is no memory leak. This code:

m = MyClass(2);

creates a temporary object of type MyClass which is copied into m using the (default-generated) copy assignment operator of MyClass, and then destructed. Eventually, p runs out of scope and its destructor destroys the MyClass instance to which is points (the one bound to m).

If we spelled out all the implicit calls explicitly, this is happening:

// std::shared_ptr<MyClass> p(new MyClass(0));
tmp1.MyClass(0);
p.shared_ptr(&tmp1);

// MyClass& m = *p;
p.operator* ();

// m = MyClass(2);
tmp2.MyClass(2);
m.operator= (tmp2);
tmp2.~MyClass();

// p goes out of scope
p.~shared_ptr();
tmp1.~MyClass();
like image 195
Angew is no longer proud of SO Avatar answered Apr 14 '26 23:04

Angew is no longer proud of SO


Do this for a more clear picture of creation destruction:

struct MyClass {
    int mId;
    MyClass(int id): mId(id) {std::cout << "Creating: " << this << "(" << mId << ")\n";}
   ~MyClass()                {std::cout << "Deleting: " << this << "(" << mId << ")\n";}
    MyClass(MyClass const& c)
                             {std::cout << "Copy:     " << this << "(" << mId << ")\n"
                                           "    From: " << &c   << "(" << c.mId << ")\n";
                              mId=c.mId;
                             }
    MyClass& operator=(MyClass const& c)
                             {std::cout << "Assign:   " << this << "(" << mId << ")\n"
                                           "    From: " << &c   << "(" << c.mId << ")\n";
                              mId=c.mId;
                             }
};

When I run I get:

Creating: 0x7fc741c000e0(0)
Creating: 0x7fff50ac38c0(2)
Assign:   0x7fc741c000e0(0)
    From: 0x7fff50ac38c0(2)
Deleting: 0x7fff50ac38c0(2)
Deleting: 0x7fc741c000e0(2)
like image 26
Martin York Avatar answered Apr 14 '26 23:04

Martin York



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!