Sergey
Sergey

Reputation: 21

Why shared_ptr doesn't call a destructor of a pointer when exception occured

I tested C++11 shared_ptr, and was surprised In this example

#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <exception>

using namespace std;

class MyExc
{

};

class Slot
{
public:
    Slot(const std::string &str = "NONAME") : m_name(str)
    {
        cout << "Constructor of slot: " << m_name << endl;
    }

    virtual ~Slot()
    {
        cout << "Destructor of slot: " << m_name << endl;
    }

    void sayName()
    {
        cout << "Slot name is: " << m_name << endl;
//       throw MyExc();
    }

private:
    string m_name;
};


void testShared(shared_ptr<Slot> & m_share)
{
    m_share->sayName();
}

int main()
{
    vector<shared_ptr<Slot>> vec {make_shared<Slot>("0"), make_shared<Slot>("1"), make_shared<Slot>("2"), make_shared<Slot>("3"), make_shared<Slot>("4")};
    for (auto& x:vec)
        testShared(x);


    return 0;
}

I see right output

Constructor of slot: 0
Constructor of slot: 1
Constructor of slot: 2
Constructor of slot: 3
Constructor of slot: 4
Slot name is: 0
Slot name is: 1
Slot name is: 2
Slot name is: 3
Slot name is: 4
Destructor of slot: 0
Destructor of slot: 1
Destructor of slot: 2
Destructor of slot: 3
Destructor of slot: 4

But if I uncomment line

throw MyExc();

output has changed, and destructor calling message didn't show

terminate called after throwing an instance of 'MyExc' Constructor of slot: 0
Constructor of slot: 1
Constructor of slot: 2
Constructor of slot: 3
Constructor of slot: 4
Slot name is: 0

Does it mean that memory leak is placed here?

Upvotes: 1

Views: 1998

Answers (1)

In your case, yes there is a memory leak (not that it matters much, since the program will terminate immediately and the OS will reclaim the memory).

To unerstand this, you need to be aware that stack unwinding (that is, destroying local variables when going up the call stack) is only guaranteed by the standard if the exception is caught. If the exception is never caught and goes straight to std::terminate, whether or not unwinding happens is up to the compiler & standard library.

Quoting C++11:

15.2:

1 As control passes from a throw-expression to a handler, destructors are invoked for all automatic objects constructed since the try block was entered. The automatic objects are destroyed in the reverse order of the completion of their construction.

3 The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.” ...

15.3:

9 If no matching handler is found, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined (15.5.1).

Upvotes: 1

Related Questions