为什么shared_ptr没有虚拟析构函数? (我该如何解决这个问题?)

发布于 2024-09-25 01:02:23 字数 639 浏览 8 评论 0原文

我想制作一个特殊版本的 shared_ptr ,在创建或销毁时执行特定操作,但我的计划似乎因 shared_ptr 的析构函数的实现而失败是非虚拟的,这意味着当我覆盖它时,当它们的最后一个实例被销毁时,我的指针永远不会被清理。

我想到的唯一替代方案是将此行为构建到我想要与假设的自定义 shared_ptr 一起使用的每个类中,但这是不可行的(或者在某些情况下是不可能的)。

编辑:

我想要这个的原因是因为我想在lua中使用一些类作为用户数据对象,并且我希望我使用这种方式的每个对象都有一个唯一的fenv表,当所有引用时该表将被清除到该对象已被删除。我计划使用指针的地址,因为它们键入保存 fenv 表的表。

假设我有一个小部件,可以将其他小部件作为子部件。我在 Lua 中创建了两个小部件,然后将其中一个设置为另一个的子部件,并删除对子部件的所有 lua 引用(事实上,它是一个子部件,是在 C++ 中处理的)。 GC 现在可以随时运行并删除子进程。不过,我不一定希望子进程运行它的析构函数,所以我想将其设为shared_ptr。这样,C++对象在Lua清理它之后仍然可以使用它。如果我已经为其 fenv 分配了值或函数,我仍然希望能够访问它们。只有当对我的子小部件的最终引用被删除时,我才希望完全删除表中的 fenv。

I wanted to make a special version of shared_ptr that would perform specific operations when it was created or destroyed, but my plans appear to be foiled by the realization that shared_ptr's destructor is non virtual, meaning when I override it, my pointers never get cleaned up when the last instance of them are destroyed.

The only alternative that comes to mind is to build in this behavior into every class that I want to use with my hypothetical custom shared_ptr, and that's not feasible (or possible in some cases).

Edit:

The reason I want this is because I want to use some classes as userdata objects in lua, and I want each one of my objects that I use this way to have a fenv table unique to it that will be cleaned up when all references to the object have been removed. I plan on using the address of the pointer as they key into a table that holds the fenv table.

Lets say I have a widget that can have other widgets as children. I create two widgets in Lua, then set one as the child of the other and remove all lua references to the child widget (the fact that it's a child is handled in C++). The GC can now run at any time and remove the child. I don't necessarily want the child to have it's destructor run though, so I want to make it a shared_ptr. That way, C++ objects can still use it after Lua has cleaned it up. If I've assigned values or functions to it's fenv I still want to be able to access them. Only when the final reference to my child widget is removed do I want the fenv tabled to be removed totally.

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

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

发布评论

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

评论(4

能否归途做我良人 2024-10-02 01:02:23

它已经内置了这种能力,不需要让人们做危险的事情,比如从中派生:

#include <boost/shared_ptr.hpp>
#include <iostream>

/*
 * Done as a function for simplicity.
 * But this can be done in so many ways
 */
void MyCleanup(int* x)
{
    std::cout << "DONE\n";
    delete x;
}

int main()
{
    boost::shared_ptr<int>  x(new int(5), MyCleanup);

}

派生问题:
就在我的头顶上。

class X: public shared_ptr<int> { /* STUFF. With a special destructor. */ };

int main()
{
    /* what happens now? Similar to slicing but not quite */
    X                data1(new int(5));
    shared_ptr<int>  data2;
    shared_ptr<int>  data3(data);

    data2 = data1;
}

It already has this ability built in without the need to let people do dangerous things like derive from it:

#include <boost/shared_ptr.hpp>
#include <iostream>

/*
 * Done as a function for simplicity.
 * But this can be done in so many ways
 */
void MyCleanup(int* x)
{
    std::cout << "DONE\n";
    delete x;
}

int main()
{
    boost::shared_ptr<int>  x(new int(5), MyCleanup);

}

Problem with deriving:
Just off the top of my head.

class X: public shared_ptr<int> { /* STUFF. With a special destructor. */ };

int main()
{
    /* what happens now? Similar to slicing but not quite */
    X                data1(new int(5));
    shared_ptr<int>  data2;
    shared_ptr<int>  data3(data);

    data2 = data1;
}
两人的回忆 2024-10-02 01:02:23

只需制作一个包装对象即可;容易多了。您可以让包装对象在其内部有一个shared_ptr实例,并且仍然使用内部对象的分配地址作为索引。这似乎比乱搞派生或自定义清理例程要好得多,除非我遗漏了一些东西。

例如:

class CWrapsLuaObject
{
    CWrapsLuaObject( LuaObject* pObject )
    { [assign internal ptr, do mapping, etc.] }

    shared_ptr< LuaObject > m_spObject;

    [...]
};

shared_ptr< CWrapsLuaObject > spInstance( new CWrapsLuaObject( pObject ) );

我是否错过了为什么这不是最简单的解决方案(没有从其他建议的解决方案中获取任何内容,这也可以工作)?

Just make a wrapper object; much easier. You can have the wrapper object have a shared_ptr instance inside it, and still use the allocation address of the internal object as an index. This seems much better than mucking around with derivation or custom cleanup routines, unless I'm missing something.

Eg:

class CWrapsLuaObject
{
    CWrapsLuaObject( LuaObject* pObject )
    { [assign internal ptr, do mapping, etc.] }

    shared_ptr< LuaObject > m_spObject;

    [...]
};

shared_ptr< CWrapsLuaObject > spInstance( new CWrapsLuaObject( pObject ) );

Am I missing why this would not be the easiest solution (not taking anything away from the other suggested solutions, which could also work)?

回心转意 2024-10-02 01:02:23

您可以提供与shared_ptr 一起使用的自定义删除对象。如果您试图将额外的信息粘贴到shared_ptr中,那么最好将其放入删除对象中。对我来说,它感觉不太干净,但它确实有效。

class ExtraThingToDestroy
{
  public:
   ~ExtraThingToDestroy() { std::cout<<"Destroying the extra thing"<<std::endl; }
};

template<typename T>
class CustomDestructor
{
  public:
    CustomDestructor( ExtraThingToDestroy * v ) : v_(v) {}
    void operator()( T* t ) { delete t; delete v_; }
    ExtraThingToDestroy * v_;
};

main()
{
   shared_ptr<int> ptr( new int, MyExtraDestructor<int>( new ExtraThingToDestroy ) );
   shared_ptr<int> ptr2 = ptr;
   //Now when ptr and all its copies get destroyed, 
   // the ExtraThingToDestroy will get deleted along with the int.
} 

You can provide a custom deletion object to be used with the shared_ptr. If you're trying to stick extra information into the shared_ptr, you may be better putting it into the deletion object. It doesn't feel very clean to me, but it works.

class ExtraThingToDestroy
{
  public:
   ~ExtraThingToDestroy() { std::cout<<"Destroying the extra thing"<<std::endl; }
};

template<typename T>
class CustomDestructor
{
  public:
    CustomDestructor( ExtraThingToDestroy * v ) : v_(v) {}
    void operator()( T* t ) { delete t; delete v_; }
    ExtraThingToDestroy * v_;
};

main()
{
   shared_ptr<int> ptr( new int, MyExtraDestructor<int>( new ExtraThingToDestroy ) );
   shared_ptr<int> ptr2 = ptr;
   //Now when ptr and all its copies get destroyed, 
   // the ExtraThingToDestroy will get deleted along with the int.
} 
羁拥 2024-10-02 01:02:23

如果您从shared_ptr派生类your_shared_ptr并覆盖析构函数,则您的析构函数应该在如下代码中调用:

{
  your_shared_ptr<int> x(new int);
}

如果您像这样使用它,则:

{
  shared_ptr<int>* ptrptr = new your_shared_ptr<int>(new int);
}

那么它不会,但您真的需要那样吗?

或者我误解了什么?

if you derive the class your_shared_ptr from shared_ptr and override the destructor, your destructor should be called in code like this:

{
  your_shared_ptr<int> x(new int);
}

If you use it like this, instead:

{
  shared_ptr<int>* ptrptr = new your_shared_ptr<int>(new int);
}

then it won't, but do you really need that?

Or am I misunderstanding something?

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