开发者

What is the deal with shared pointer?

My program fails due to addition of a pointer to a vector. After much reading and deletin开发者_如何学运维g I have changed it to an addition of a shared pointer into a set (using insert) which was fine at first but now fails as well. I tried two solutions; neither worked. One failed as well and the other, the make shared kind, did not compile.

Reading a bit more I came upon this forum which states, that I shouldn't point to something with two different shared pointers but rather create a copy of it. So what is the big difference of the shared pointer...?


It's all about ownership. An entity (a function or object) is said to "own" a pointer if it is that entity's job to ensure that the pointer is deleted. Any time you use new, someone, somewhere must take ownership of the pointer returned. If this is not the case, you have a memory leak.

The purpose of all kinds of smart pointers is to model some form of ownership. The destructor of the smart pointer is what can trigger the deletion of the pointer.

std::auto_ptr (as long as you don't copy it) models single-ownership. That is, whatever entity has the auto_ptr instance is the entity that will cause that pointer's destruction. Thanks to hackery, copying an auto_ptr actually transfers ownership from the copied object to the object being copied to (note: never do this).

So, if you have this:

std::auto_ptr<int> p1 = new int(4);

This is guaranteed to be destroyed (so long as the entity holding it is properly cleaned up). When p1 falls off the stack, the pointer will be destroyed. If p1 were a member of a class, then the pointer will be destroyed when that class instance is destroyed. The lifetime of the pointer is scoped. Boost actually has a non-copyable equivalent called boost::scoped_ptr.

There are several rules that you must abide by when using any kind of smart pointers. This is the most important.

Rule #1: If you construct a smart pointer instance from a naked pointer, what you are saying is, "No object currently has ownership of this pointer. I am now giving ownership to you, the smart pointer." That is what it means to construct a smart pointer object from a naked pointer.

This code is a violation of Rule #1:

std::auto_ptr<int> p1 = new int(4);
std::auto_ptr<int> p2 = p1.get();

The auto_ptr::get() function returns the pointer, so this is legal C++ code (it compiles). However, both p1 and p2 now think that they own the pointer. Because auto_ptr only models single-ownership, that is not allowed. When p2 is destroyed, it will delete the pointer. Then, when p1 is destroyed, it will try to delete the same pointer.

Oops.

Now that we're all very clear on Rule #1, let's look at shared_ptr. This smart pointer models shared ownership. Multiple entities can claim ownership of the pointer at the same time. The pointer will only be deleted when all of them are finished using it. So if 3 objects all contain a shared_ptr to the same object, that object will not be deleted until all three that contain the shared_ptr are deleted.

It is important to understand that shared_ptr is a smart pointer. And therefore, it is subject to Rule #1.

That may not make sense. After all, it's supposed to allow shared ownership. That must mean that this is allowable, right?

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1.get();

Nope. This is still wrong. The difference between auto_ptr and shared_ptr is that you can do this with shared_ptr:

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1;

That's copy construction of p2 from p1. There is a fundamental difference between creating a shared_ptr from a naked pointer and creating one from an already existing shared_ptr. The latter is what actually shares ownership between the two. The former will just cause badness.

Therefore, if you ever have a naked pointer and put it in a shared_ptr, you can only do this for that pointer one time. If you want to share ownership, you must copy it around.

There is one semi-backdoor: enable_shared_from_this. If you derive a class from this type, then your class will have a shared_from_this private member that member functions of the class can use to transfer ownership around. So:

struct Type : public enable_shared_from_this
{
  DoSomething()
  {
    shared_ptr<Type> p2 = shared_from_this();
    FunctionThatTakesOwnership(p2);
  }
};

shared_ptr<Type> p1 = new Type;
p1->DoSomething();

Other than that, you'll have to transfer ownership by explicitly copying the object around.


shared_ptr, as its name states, should be used if an object, pointed by shared_ptr, is referenced from different places.

For example - class A1 and A2 should use same object of type S. So both should hold pointer to S. But who exclusively owns its (who should delete it). Let's say A1. So, A1 in its destructor will delete S. But what happen if A1 is destroyed before A2 - A2 will have dangling pointer (pointer to deleted object) to S. Using shared_ptr instead of raw pointer to S (S*) solves this problem.


The shared pointer takes ownership of the object pointed to.

The semantics of this is that when the shared_ptr is copied, each in turns shares a handle to their shared knowledge of the ownership. When the last copy is destroyed, it destroys the object. This saves you from having to manually manage the call to delete at the right time, and (hopefully) make memory leaks rarer.

To make this work, the normal style is to give a new heap object to a shared_ptr when it is created, and avoid thereafter directly working with the raw pointer.

You are correct in using shared_ptr within the STL set. This is the right way to ensure that the object is cleaned up when the set is destroyed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜