简体   繁体   English

具有 unique_ptr 的受保护析构函数

[英]protected destructor with unique_ptr

I am trying to call APIs from a third party library.我正在尝试从第三方库调用 API。

There is a trouble when I want to use unique_ptr with a class having protected destructor.当我想将 unique_ptr 与具有受保护析构函数的 class 一起使用时会出现问题。

Here is the example,这是示例,

#include <memory>
#include <iostream>

using namespace std;

class Parent {  
  public:  
    Parent () //Constructor
    {
        cout << "\n Parent constructor called\n" << endl;
    }
  protected:
    ~ Parent() //Dtor
    {
        cout << "\n Parent destructor called\n" << endl;
    }
};

class Child : public Parent 
{
  public:
    Child () //Ctor
    {
        cout << "\nChild constructor called\n" << endl;
    }
    ~Child() //dtor
    {
        cout << "\nChild destructor called\n" << endl;
    }
};

Parent* get() {
  return new Child();
}

int main(int argc, char const* argv[])
{
  Parent * p1 = get(); // this is ok
  std::unique_ptr<Parent> p2(get()); // this is not ok
  return 0;
}

I am trying to use unique_ptr with Parent class.我正在尝试将 unique_ptr 与父 class 一起使用。 But the compiler threw the errors但是编译器抛出了错误

/usr/include/c++/5/bits/unique_ptr.h: In instantiation 
of ‘void std::default_delete<_Tp>::operator()(_Tp*) const 
[with _Tp = Parent]’:
/usr/include/c++/5/bits/unique_ptr.h:236:17:   required 
from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp 
= Parent; _Dp = std::default_delete<Parent>]’
main.cpp:38:35:   required from here
main.cpp:12:5: error: ‘Parent::~Parent()’ is protected
 ~ Parent() //Dtor
 ^
In file included from /usr/include/c++/5/memory:81:0,
             from main.cpp:2:
/usr/include/c++/5/bits/unique_ptr.h:76:2: error: within 
this context
  delete __ptr;

Any idea about getting rid of this issue?关于摆脱这个问题的任何想法? I can't hack Parent and Child class since they are the classes of the third party library.我不能破解 Parent 和 Child class 因为它们是第三方库的类。

You can make std::default_delete<Parent> a friend of Parent to fix that error. 你可以std::default_delete<Parent>的朋友Parent来修复错误。 And you may also like to make ~Parent virtual to avoid undefined behaviour when delete ing a derived class through Parent pointer. 而且,您也可能希望将~Parent virtual以避免在通过Parent指针delete派生类时发生未定义的行为。

Eg: 例如:

class Parent { 
    friend class std::default_delete<Parent>;
    // ...
protected:
    virtual ~Parent();
    // ...

However, Parent design makes it clear that you are not supposed to delete through Parent pointer, this is why the destructor is non-public. 但是, Parent设计清楚表明您不应该通过Parent指针delete ,这就是为什么析构函数是非公共的。 Read Virtuality for more details: 阅读虚拟性以了解更多详细信息:

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual. 准则4:基类的析构函数应该是公共的和虚拟的,或者是受保护的并且是非虚拟的。


You may like to introduce another intermediate base class to solve the issue: 您可能想引入另一个中间基类来解决此问题:

class Parent { // Comes from a 3rd-party library header.
protected:
    ~Parent();
};

struct MyParent : Parent {  // The intermediate base class.
    virtual ~MyParent();
};

class Derived : public MyParent {};

std::unique_ptr<MyParent> createDerived() {
    return std::unique_ptr<MyParent>(new Derived);
}

int main() {
    auto p = createDerived();
}

Unfortunately, the real way to get rid of this issue is to not derive classes from Parent , and to not manage the lifetime of Parent objects (or any derived classes) using std::unique_ptr<Parent> . 不幸的是,摆脱此问题的真正方法是不从Parent派生类,并且不使用std::unique_ptr<Parent>来管理Parent对象(或任何派生类)的生存期。

In other words, you need to redesign your classes. 换句话说,您需要重新设计您的类。

The reasons I say this are 我说这的原因是

  • If someone has gone to the trouble of giving Parent a protected non-virtual destructor, the intent is most likely to avoid having a Parent * which actually points at an instance of a derived class and is released using operator delete . 如果有人麻烦给Parent一个受保护的非虚拟析构函数,则该意图最有可能避免使用Parent * ,后者实际上指向派生类的实例,并使用运算符delete释放。 A library designer will not (normally) do this without good reason. 库设计人员没有正当理由不会(通常)这样做。
  • Your code can be forced to compile as is (eg by making std::default_delete<Parent> a friend of Parent ). 您的代码可以被强制编译原样(例如,通过使std::default_delete<Parent>的一个朋友Parent )。 However, std::default_delete is used by unique_ptr to release the managed object. 但是, unique_ptr使用std::default_delete释放托管对象。 And it uses operator delete . 并且它使用运算符delete That gives undefined behaviour if the object being managed by the unique_ptr<Parent> is of a type derived from Parent . 如果由unique_ptr<Parent>管理的对象是从Parent派生的类型,则将产生未定义的行为。

So, in short, you're working around the intent of (whoever designed) your third party library and, if you force the code to compile anyway, your reward will be undefined behaviour. 因此,简而言之,您正在努力(无论是由谁设计的)第三方库的意图,并且,如果您无论如何都迫使代码进行编译,则您的报酬将是不确定的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM