Reputation: 21
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
Reputation: 171117
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 tostd::terminate()
is implementation-defined (15.5.1).
Upvotes: 1