shared_ptr 删除对象

发布于 2024-12-04 00:31:10 字数 277 浏览 0 评论 0原文

void ClassName::LocalMethod( )
{
    boost::shared_ptr<ClassName> classNamePtr( this );

    //some operation with classNamePtr
    return;
}

这里,当对象从 LocalMethod() 返回时,它会被释放,因为 classNamePtr 超出了范围。难道shared_ptr不够聪明,知道ClassName对象仍在范围内而不删除它吗?

void ClassName::LocalMethod( )
{
    boost::shared_ptr<ClassName> classNamePtr( this );

    //some operation with classNamePtr
    return;
}

Here the object is getting released when it returns from LocalMethod() since classNamePtr is out of scope. Isn't the shared_ptr smart enough to know that the ClassName object is still in scope and not to delete it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情深缘浅 2024-12-11 00:31:10

为对象创建 shared_ptr 意味着什么?这意味着 shared_ptr 的持有者现在承担了该对象的所有权。所有权意味着该对象将在他愿意时被删除。当 shared_ptr 的持有者销毁其 shared_ptr 时,这将导致该对象可能被销毁,假设没有其他 shared_ptr 可以销毁那个物体。

shared_ptr是类的成员时,这意味着shared_ptr指向的对象的生命周期至少只要shared_ptr 所属的对象。当 shared_ptr 位于堆栈上时,这意味着 shared_ptr 所指向的对象的生命周期至少与创建它的作用域一样长。一旦对象从堆栈中掉出,它就可能被删除。

唯一您应该获取指针并将其包装到shared_ptr中的时间是您最初分配对象时 >。为什么?因为对象不知道它是否在shared_ptr中。它不可能知道。这意味着创建原始 shared_ptr 的人现在有责任将其传递给需要共享该内存所有权的其他人。共享所有权的唯一工作方式是通过 shared_ptr复制构造函数。例如:

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

shared_ptr 的复制构造函数在 p1p3 之间创建共享所有权。请注意,p2 不与 p1 共享所有权。他们都认为自己拥有相同的内存,但这与共享它不同。因为他们都认为自己拥有它唯一的所有权。

因此,当三个指针被销毁时,会发生以下情况。首先,p3 将被销毁。但由于 p3 和 p1 共享该整数的所有权,因此该整数还不会被销毁。接下来,p2 将被销毁。由于它认为自己是该整数的唯一持有者,因此它将销毁它。

此时,p1 指向已删除的内存。当p1被销毁时,它认为它是该整数的唯一持有者,因此它将销毁它。这是,因为它已经被摧毁了。

你的问题是这样的。您位于类的实例内。并且您需要调用一些带有 shared_ptr 的函数。但您拥有的只是 this,它是一个常规指针。你做什么工作?

您将获得一些建议 enable_shared_from_this 的示例。但考虑一个更相关的问题:“为什么这些函数采用 shared_ptr 作为参数?”

函数采用的指针类型指示该函数对其参数执行的操作。如果函数采用shared_ptr,则意味着它需要拥有指针。它需要共享内存所有权。因此,请检查您的代码并询问这些函数是否确实需要获得内存的所有权。他们是否将 shared_ptr 长期存储在某个地方(即:在一个对象中),或者只是在函数调用期间使用它们?

如果是后者,那么函数应该采用裸指针,而不是 shared_ptr。这样,他们就无法主张所有权。然后,您的接口是自记录的:指针类型解释了所有权。

但是,您可能正在调用真正需要共享所有权的函数。那么你需要使用enable_shared_from_this。首先,您的类需要从 enable_shared_from_this 派生。然后,在函数中:

void ClassName::LocalMethod()
{
    boost::shared_ptr<ClassName> classNamePtr(shared_from_this());

    //some operation with classNamePtr
    return;
}

注意,这里有一个成本。 enable_shared_from_this 在类中放置一个 boost::weak_ptr 。但没有虚拟开销或类似的东西;它不会使课堂变得虚拟。 enable_shared_from_this 是一个模板,因此您必须像这样声明它:

class ClassName : public boost::enable_shared_from_this<ClassName>

What does it mean to create a shared_ptr to an object? It means that the holder of the shared_ptr now assumes ownership over the object. Ownership meaning that the object will be deleted when he so desires. When the holder of the shared_ptr destroys its shared_ptr, that will cause the object to potentially be destroyed, assuming that there are no other shared_ptrs to that object.

When a shared_ptr is a member of a class, that means that the lifetime of the object pointed to by the shared_ptr is at least as long as the object that the shared_ptr is a member of. When a shared_ptr is on the stack, this means that the lifetime of the object that the shared_ptr is pointing to will be at least as long as the scope it was created in. Once the object falls off the stack, it may be deleted.

The only time you should ever take a pointer and wrap it into a shared_ptr is when you are allocating the object initially. Why? Because an object does not know whether it is in a shared_ptr or not. It can't know. This means that the person who creates the original shared_ptr now has the responsibility to pass it around to other people who need to share ownership of that memory. The only way shared ownership works is through the copy constructor of shared_ptr. For example:

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

The copy constructor of shared_ptr creates shared ownership between p1 and p3. Note that p2 does not share ownership with p1. They both think they have ownership over the same memory, but that's not the same as sharing it. Because they both think that they have unique ownership of it.

Therefore, when the three pointers are destroyed, the following will happen. First, p3 will be destroyed. But since p3 and p1 share ownership of the integer, the integer will not be destroyed yet. Next, p2 will be destroyed. Since it thinks that it is the only holder of the integer, it will then destroy it.

At this point, p1 is pointing to deleted memory. When p1 is destroyed, it thinks that it is the only holder of the integer, so it will then destroy it. This is bad, since it was already destroyed.

Your problem is this. You are inside an instance of a class. And you need to call some functions of yours that take a shared_ptr. But all you have is this, which is a regular pointer. What do you do?

You're going to get some examples that suggest enable_shared_from_this. But consider a more relevant question: "why do those functions take a shared_ptr as an argument?"

The type of pointer a function takes is indicative of what that function does with its argument. If a function takes a shared_ptr, that means that it needs to own the pointer. It needs to take shared ownership of the memory. So, look at your code and ask whether those functions truly need to take ownership of the memory. Are they storing the shared_ptr somewhere long-term (ie: in an object), or are they just using them for the duration of the function call?

If it's the latter, then the functions should take a naked pointer, not a shared_ptr. That way, they cannot claim ownership. Your interface is then self-documenting: the pointer type explains ownership.

However, it is possible that you could be calling functions that truly do need to take shared ownership. Then you need to use enable_shared_from_this. First, your class needs to be derived from enable_shared_from_this. Then, in the function:

void ClassName::LocalMethod()
{
    boost::shared_ptr<ClassName> classNamePtr(shared_from_this());

    //some operation with classNamePtr
    return;
}

Note that there is a cost here. enable_shared_from_this puts a boost::weak_ptr in the class. But there is no virtual overhead or somesuch; it doesn't make the class virtual. enable_shared_from_this is a template, so you have to declare it like this:

class ClassName : public boost::enable_shared_from_this<ClassName>
迷途知返 2024-12-11 00:31:10

shared_ptr 不是足够聪明,知道 ClassName 对象是
仍在范围内而不删除它?

这不是 shared_ptr 的工作原理。当您在构造 shared_ptr 时传递指针时,shared_ptr 将取得指针对象的所有权(在本例中为 *this< /代码>)。换句话说,由于 shared_ptr 现在拥有指针对象,因此 shared_ptr 承担了对指针对象生命周期的完全控制。因此,最后一个拥有该指针的 shared_ptr 将删除它。

如果 ClassName::LocalMethod() 之外没有 classNamePtr 的副本,您可以传递一个在构造 时不执行任何操作的删除器>classNamePtr下面是一个用于防止 < code>shared_ptr 删除其指针对象。根据您的情况调整示例:

struct null_deleter // Does nothing
{
    void operator()(void const*) const {}
};

void ClassName::LocalMethod() 
{
    // Construct a shared_ptr to this, but make it so that it doesn't
    // delete the pointee.
    boost::shared_ptr<ClassName> classNamePtr(this, null_deleter()); 
    // Some operation with classNamePtr 

    // The only shared_ptr here will go away as the stack unwinds,
    // but because of the null deleter it won't delete this.
    return; 
}

您还可以使用 enable_shared_from_thisthis 获取 shared_ptr。请注意,成员函数 shared_from_this() 仅当现有 shared_ptr 已指向 this 时才起作用。

class ClassName : public enable_shared_from_this<ClassName> 
{ 
public: 
    void LocalMethod()
    { 
        boost::shared_ptr<ClassName> classNamePtr = shared_from_this(); 
    } 
} 

// ...

// This must have been declared somewhere...
shared_ptr<ClassName> p(new ClassName);
// before you call this:
p->LocalMethod();

这是更合适的“官方”方法,并且比空删除器方法要简单得多。

也可能您实际上并不需要首先创建 shared_ptr//some operation with classNamePtr 注释部分包含哪些内容?可能还有比前两种方法更好的方法。

Isn't the shared_ptr smart enough to know that the ClassName object is
still in scope and not to delete it?

That's not how shared_ptr works. When you pass a pointer while constructing a shared_ptr, the shared_ptr will assume ownership of the pointee (in this case, *this). In other words, the shared_ptr assumes total control over the lifetime of the pointee by virtue of the fact that the shared_ptr now owns it. Because of this, the last shared_ptr owning the pointee will delete it.

If there will be no copies of classNamePtr outside of ClassName::LocalMethod(), you can pass a deleter that does nothing while constructing classNamePtr. Here's an example of a custom deleter being used to prevent a shared_ptr from deleting its pointee. Adapting the example to your situation:

struct null_deleter // Does nothing
{
    void operator()(void const*) const {}
};

void ClassName::LocalMethod() 
{
    // Construct a shared_ptr to this, but make it so that it doesn't
    // delete the pointee.
    boost::shared_ptr<ClassName> classNamePtr(this, null_deleter()); 
    // Some operation with classNamePtr 

    // The only shared_ptr here will go away as the stack unwinds,
    // but because of the null deleter it won't delete this.
    return; 
}

You can also use enable_shared_from_this to obtain a shared_ptr from this. Note that the member function shared_from_this() only works if you have an existing shared_ptr already pointing to this.

class ClassName : public enable_shared_from_this<ClassName> 
{ 
public: 
    void LocalMethod()
    { 
        boost::shared_ptr<ClassName> classNamePtr = shared_from_this(); 
    } 
} 

// ...

// This must have been declared somewhere...
shared_ptr<ClassName> p(new ClassName);
// before you call this:
p->LocalMethod();

This is the more appropriate, "official" method and it's much less hackish than the null deleter method.

It could also be that you don't actually need to create a shared_ptr in the first place. What goes into the section commented //some operation with classNamePtr? There might be an even better way than the first two ways.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文