Smart Pointers Confusion

Started by
2 comments, last by Servant of the Lord 10 years, 1 month ago

Hello,

I was playing around with smart pointers in C++ (VS2010) and encountered some unexpected behavior. Best explained by this code snippet:


// allocate the memory
Test* dynamic = new Test;
 
// take over the ownership
std::unique_ptr<Test> takeOver(dynamic);
 
// wait for ENTER to continue
std::getchar();
 
// clear the memory
takeOver.reset();
 
// shouldn't this cause a crash?
dynamic->reference(1);
 
// oddly enough the following line doesn't cause an immediate crash either
// if I press ENTER next though, it crashes and the debugger says that it might be due to heap corruption
//delete dynamic;
 
std::getchar();

Output I get from the application is the following:

Constructing test...
Destroying test...
accessing func for owner 1
From what I can gather, the memory does get freed since a second delete call causes heap corruption. However, why is the original pointer still valid and prints out the result from that function call?
Any help would greatly be appreciated and thanks in advance!
Advertisement

Calling a member function on a deleted object is undefined behavior, which often means a crash, but can really do anything at all including succeeding. In this case I'm guessing that your member function doesn't actually use any member variables so doesn't actually access any deleted memory.

Calling a member function on a deleted object is undefined behavior, which often means a crash, but can really do anything at all including succeeding. In this case I'm guessing that your member function doesn't actually use any member variables so doesn't actually access any deleted memory.

Ah, of course. Indeed, as soon as I added a member variable, the function returned junk values. Just to be certain though, I allocated memory for an int in the constructor, then in the destructor deleted it and set the pointer to NULL and then had the original pointer query that member function that returned the variable's value and the application crashed as expected. Thanks for the quick reply!

Even if does did use member variables, why should the code bother wasting processing power clearing or zero-ing out the deleted memory? (though in debug mode it might)

It could be "deleted' but the bytes don't have to change that quickly if nothing else happens to use that now-available piece of memory; the bytes could possibly still even return the correct result without crashing, even after being deleted. Undefined behavior.

Many a hard-to-track bug result from manually managing memory or mixing up pointers. mellow.png

That's one of the things smart pointers aim to prevent.

A safer way to create a smart pointer is to use the std::make_ functions:


std::shared_ptr<Type> myPtr = std::make_shared<Type>(3.14f, "Type's parameters");
std::unique_ptr<Type> myPtr = std::make_unique<Type>(...);

If your compiler doesn't have std::make_unique yet, here's a placeholder until it gets it:


//std::make_unique implementation (it was forgotten in the C++11 standard, and will be added later).
//Once it's added, I can just remove this from here.
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
	return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

You already have std::make_shared.

Aside from a small behind-the-scenes optimization, the std::make_ functions are safer.

This topic is closed to new replies.

Advertisement