Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Smart Pointers Confusion


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 dr4cula   Members   -  Reputation: 310

Like
1Likes
Like

Posted 22 February 2014 - 10:38 AM

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!


Sponsor:

#2 SiCrane   Moderators   -  Reputation: 9800

Like
6Likes
Like

Posted 22 February 2014 - 10:46 AM

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.



#3 dr4cula   Members   -  Reputation: 310

Like
0Likes
Like

Posted 22 February 2014 - 11:11 AM

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!



#4 Servant of the Lord   Crossbones+   -  Reputation: 22758

Like
4Likes
Like

Posted 22 February 2014 - 11:59 AM

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.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS