C++ 中的智能指针

发布于 2024-11-03 08:35:19 字数 636 浏览 7 评论 0原文

假设我们有一个类和一个派生类。所以:

class base {
     protected:
          ~base(){
                //...
          }
     // ...
};

class derived : public base {
     // ...
};

现在假设我们使用上面的类和智能指针类来编写此代码:

SmartPointer<base> bptr(new derived());
delete bptr;

我知道它会通过调用派生的析构函数来防止对派生对象进行切片>,但是它怎么知道要这样做呢?存储在智能指针中的引用不应该是base*类型的引用吗?它是否遍历某种层次结构树,将该指针强制转换为衍生*,然后调用删除?还是还有什么我不知道的事情?

该实现据称是线程安全的、非侵入式的和引用计数的。

,您看到的类与我正在测试的类类似。显然有一种方法可以通过这些给定的类来做到这一点。我在上面的问题中提到了关于如何实现的主要想法,但我不确定这样的实现将如何工作。

Say we have a base class and a derived. So:

class base {
     protected:
          ~base(){
                //...
          }
     // ...
};

class derived : public base {
     // ...
};

And now say that we have this code using the above classes with a smart pointer class:

SmartPointer<base> bptr(new derived());
delete bptr;

I understand that it would prevent slicing of the derived object by calling the destructor of derived, but how does it know to do that? Wouldn't the reference stored in the smart pointer be that of type base*? Does it traverse some kind of hierarchy tree, cast that pointer to derived* and then call delete? Or is there some other thing that I don't know about?

The implementation is supposedly threadsafe, non-intrusive, and reference counting.

YES, the classes that you see are akin to the ones that I'm testing against. There is apparently a way to do this with THESE GIVEN classes. The main idea as to how is mentioned in my question above, but I'm not sure as to how one such an implementation would work.

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

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

发布评论

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

评论(5

笨死的猪 2024-11-10 08:35:19

首先,就目前的情况来看,代码将无法工作。 base 的析构函数至少必须受到protected(或者派生类是基类的友元)。 private 析构函数意味着编译器不允许您为派生类编写析构函数。现在,假设您有一个受保护的析构函数...(请记住,如果您设计要扩展的类,请提供一个公共虚拟析构函数或一个受保护的析构函数)非虚拟!)

一切都取决于SmartPointer的实现,特别是std::shared_ptr(或boost对应的boost::shared_ptr)能够干净地管理这种情况。该解决方案出于破坏目的执行某种类型的部分类型擦除。基本上,智能指针有一个模板化构造函数,它接受任何可以分配给基指针的指针,但因为它是模板化的,所以它知道具体类型。此时,它存储一个合成的删除器函数,该函数将调用适当的析构函数。

为简单起见,使用 std::function

template <typename T>
void delete_deleter( void * p ) {
   delete static_cast<T*>(p);
}

template <typename T>
class shared_pointer {
    T * ptr;
    std::function<void(void*)> deleter;
public:
    template <typename U>
    shared_pointer( U* p, std::function<void()> d = delete_deleter<U> ) 
       : ptr(p), deleter(d)
    {}
    ~shared_pointer() {
       deleter( ptr );  // call the stored destructor
    }
};

该代码仅用于展示,必须针对生产进行调整(在哪里存储 function、引用计数... ),但这足以让您了解:在唯一已知对象确切类型的函数中(创建智能指针时),您创建一个包装器,它将调用您需要的析构函数的确切版本(提供一些类型擦除的缺陷),然后将其保留,当您需要删除对象时,调用它而不是delete运算符。

这也可以用于管理需要调用特殊方法而不是删除的其他资源:

// exhibition only!
shared_pointer<Foo> p( Factory.create(), &Factory::release );

同样,在准备好此生产之前应该有相当多的工作。

可以消除对用于简化擦除的 std::function 的依赖。在简单的情况下(智能指针仅支持使用 new 分配内存并使用 delete 释放内存),则只需提供一个 deleter 基类使用单个虚拟 operator()(void*),然后将现有的 delete_deleter 重构为覆盖 deleter 的模板化派生类使用当前实现的operator()(void*)。如果您需要处理一般情况(保存任何类型的资源),那么不值得付出努力,只需使用 std::functionboost::function 即可。

First thing is that as it stands the code will not work. The destructor of base must be at the very least protected (or derived classes be friends of the base). A private destructor means that the compiler will not allow you to write the destructor for the derived classes. Now, assuming that you have a protected destructor... (Rembember, if you design a class to be extended, provide either a public virtual destructor or a protected non-virtual!)

All depends on the implementation of the SmartPointer, in particular std::shared_ptr (or the boost counterpart boost::shared_ptr) are able to manage that situation cleanly. The solution performs some sort of partial type erasure of the type for destruction purposes. Basically, the smart pointer has a templated constructor that accepts any pointer that can be assigned to a base pointer, but because it is templated it knows the concrete type. At that point it stores a synthetic deleter function that will call the appropriate destructor.

For simplicity, using std::function:

template <typename T>
void delete_deleter( void * p ) {
   delete static_cast<T*>(p);
}

template <typename T>
class shared_pointer {
    T * ptr;
    std::function<void(void*)> deleter;
public:
    template <typename U>
    shared_pointer( U* p, std::function<void()> d = delete_deleter<U> ) 
       : ptr(p), deleter(d)
    {}
    ~shared_pointer() {
       deleter( ptr );  // call the stored destructor
    }
};

The code is for exhibition only, it would have to be tweaked for production (where to store the function, reference counting...), but it is enough to give you the idea: in the only function where the exact type of the object is known (when creating the smart pointer), you create a wrapper that will call the exact version of the destructor that you need (providing some short of type erasure), then just leave it around and when you need to delete the object call it instead of the delete operator.

This can also be used to manage other resources that require calling a special method instead of delete:

// exhibition only!
shared_pointer<Foo> p( Factory.create(), &Factory::release );

Again there should be quite a lot of work before making this production ready.

Dependency on std::function which is used to simplify the erasure, can be eliminated from the problem. In the simple case (only memory allocated with new and freed with delete is supported in the smart pointer), then just provide a deleter base class with a single virtual operator()(void*), and then refactor the existing delete_deleter into templated derived classes from deleter that override operator()(void*) with the current implementation. If you need to go for the general case (hold any type of resource) it is not worth the effort, just use std::function or boost::function.

凤舞天涯 2024-11-10 08:35:19

首先,你的析构函数不应该是私有的,否则根本无法编译。其次,如果您使用“智能指针”,您可能根本不应该手动删除指针(虽然我不知道您正在使用什么实现,但这对我来说很奇怪)。

无论如何,如果您好奇当通过指向基类的指针删除对象时如何调用派生类的析构函数,答案就是多态性。但是您的析构函数缺少 virtual 声明,现在您的代码不会调用派生类的析构函数。

大多数 C++ 实现是通过虚拟表来实现这一点的。

Well first of all, your destructor shouldn't be private or that won't compile at all. Secondly, if you're using a "smart pointer", you probably should not be deleting the pointer by hand at all (I don't know what implementation you're using though, but this strikes as odd to me).

Anyways if you're curious how the derived class' destructor gets called when the object is deleted through a pointer to the base class, the answer is polymorphism. But you're missing virtual declaration from your destructor, right now your code would not call the derived class' destructor.

How most C++ implementations implement this is through a virtual table.

巷子口的你 2024-11-10 08:35:19

如果您使用任何 boost 智能指针或其他不是您的 Base 类的 friend 的指针,那么此代码将无法编译,因为 Base< 的析构函数/code> 类是 protected (与其他独立于 Base 类的 private 相同)。

现在让我们假设您将 SmartPointer 设为 Base 的友元。在这种情况下,代码可以工作,但它不会调用 Derived 的析构函数,而是调用 Base 的析构函数,因为这里您的 Base 类不是多态的。您应该将Base 的destrucotr 声明为virtual。在最后一种情况下,当您的智能指针被删除时,将调用正确的析构函数。

If you using any of boost smart pointers or some other which is not friend of your Base class, then this code wouldn't compile, because destructor of Base class is protected (which is same as private for other independent from Base classes).

Now let's consider that you make SmartPointer<Base> friend of Base. This case the code will work, but it wouldn't call destructor of Derived but destructor of Base, because here your Base class is not polymorphic. You should declare destrucotr of Base as virtual. In last case the correct destructor will be called when your smart pointer is deleted.

非要怀念 2024-11-10 08:35:19

该程序无效。

1)base的dtor是私有的

2)base的dtor不是虚拟的

来回答你的问题:你需要更正#1和#2。 然后将使用动态调度来调用 dtor(这将以与构造相反的顺序调用每个 dtor)。

如果不进行这些更正,SmartPointer 能够知道在此示例中以定义的方式调用派生的 dtor 的唯一方法是 SmartPointer 是否过于聪明(或使用起来很乏味) )。

this program is invalid.

1) the dtor of base is private

2) the dtor of base is not virtual

to answer your question: you need to correct #1 and #2. then the dtor will be called using dynamic dispatch (which will invoke each dtor in reverse order of construction).

without making those corrections, the only way SmartPointer could know to call derived's dtor in this example, and in a defined manner, is if SmartPointer was overly clever (or tedious to use).

初心 2024-11-10 08:35:19

您的基类析构函数需要是虚拟的,以确保在通过基指针删除时调用派生类的析构函数。

有关虚拟析构函数的维基百科条目

Your base class desctructor needs to be virtual to ensure that destructor of derived class is called when deleting via base pointer.

Wikipedia entry on virtual desctructors

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