C++ 我可以解决独特的问题吗\u ptr<;MyType>;仅存储nullptr时是否不需要MyType析构函数定义?

C++ 我可以解决独特的问题吗\u ptr<;MyType>;仅存储nullptr时是否不需要MyType析构函数定义?,c++,c++11,destructor,definition,interface-implementation,C++,C++11,Destructor,Definition,Interface Implementation,我需要使用VS2012编译器并具有: virtual std::unique_ptr<MyType> pass_through(std::unique_ptr<MyType> instance) override { return std::unique_ptr<MyType>(nullptr); }; 这就是问题所在,我不想因为上面的函数通过构建而产生混乱的定义。。那么,有没有一种方法不需要指定析构函数定义,并且仍然可以有效地实现该pass_-throug

我需要使用VS2012编译器并具有:

virtual std::unique_ptr<MyType> pass_through(std::unique_ptr<MyType> instance) override { return std::unique_ptr<MyType>(nullptr); };
这就是问题所在,我不想因为上面的函数通过构建而产生混乱的定义。。那么,有没有一种方法不需要指定析构函数定义,并且仍然可以有效地实现该pass_-through方法

也许我可以通过某种方式更改方法的签名或其逻辑,以便在主要实现中基本上执行相同的操作,它执行如下操作:

std::unique_ptr<MyType> pass_through(std::unique_ptr<MyType> instance)
{
    if (!instance) {
        instance= std::unique_ptr<MyType>(new MyType(/*arguments*/));
    }
    instance->something();
    return instance;
}
std::unique\u ptr pass\u through(std::unique\u ptr实例)
{
如果(!实例){
instance=std::unique_ptr(新的MyType(/*参数*/);
}
实例->某物();
返回实例;
}

顺便说一句,我看到类似的问题被否决/关闭,但在建议中我没有看到任何相关的答案,我以前也使用过谷歌,但仍然没有点击=>可能会以某种方式促进相关问题的良好答案,如果有的话?

你不需要在同一个编译单元中定义。我认为你错了。(包含
void MyType::something(){/*…*/}
的.cpp文件也应该具有
MyType::~MyType(){/*…*/}
,因此如果您使用
(MyType*)->something
,您应该能够使用析构函数)

如果这确实是您想要做的(编译程序的一小部分而不将单元与析构函数链接,无论出于何种原因),那么使用默认的
std::unique_ptr
是不可能的,它需要调用
delete(T*),最终需要析构函数可用

您可以使用自定义删除器,在特殊情况下可以使用“不做任何事情”删除器。这意味着您不需要
MyType::~MyType
符号:

#include <memory>

class MyType {
public:
    void something();

    ~MyType();
};

// `MyUniquePtr` calls a stored function pointer to delete it's value
using MyUniquePtr = std::unique_ptr<MyType, void(*)(const MyType*) noexcept>;

void MyTypeDeleter(const MyType* p) noexcept;

// This is compatible with `MyUniquePtr`'s deleter, and does nothing when called
void MyTypeNullDeleter(const MyType* p) noexcept {
    // For extra safety add this check
    if (p != nullptr) std::terminate();

    // Otherwise do nothing
    // (Don't need to delete a nullptr, don't need a destructor symbol)
}

MyUniquePtr pass_through(MyUniquePtr instance) {
    return MyUniquePtr(nullptr, MyTypeNullDeleter);
};

但是,很容易意外地将“不做任何事情”的删除程序分配给非空指针。

我认为一个问题有几个方面。 首先是了解独特的ptr的功能:

它将以RAII方式包装您的类,并保持指向您的类的指针,并在被销毁或重新签名时释放它。为了确保我们在同一页上,让我们探讨一下unique_ptr的示例实现(摘自问题):

模板
类唯一\u ptr{
私人:
T*_ptr;
公众:
唯一ptr(T&T){
_ptr=&t;
}
唯一的\u ptr(唯一的\u ptr&uptr){
_ptr=std::move(uptr.\u ptr);
uptr.\u ptr=nullptr;
}
~unique_ptr(){
删除(ptr);;
}
唯一\u ptr&运算符=(唯一\u ptr&uptr){
如果(this==uptr)返回*this;
_ptr=std::move(uptr.\u ptr);
uptr.\u ptr=nullptr;
归还*这个;
}
唯一性(const unique_ptr&uptr)=删除;
唯一\u ptr&运算符=(常量唯一\u ptr&uptr)=删除;
};
如您所见,unique指针析构函数在~unique_ptr()函数中对实际对象调用delete

现在让我们看看标准:

3.7.4动态存储持续时间[basic.stc.Dynamic]1在程序执行期间(1.9),可以使用 新表达式(5.3.4),并使用删除表达式销毁 (5.3.5). 一个C++实现提供了访问和管理, 通过全局分配功能的动态存储和新的 运算符new[]和全局解除分配函数运算符delete 和运算符删除[]

此外:

如果删除表达式的操作数的值不是null 指针值时,删除表达式将调用析构函数(如果 任何)用于要删除的对象或数组元素。在 对于数组,元素将按顺序销毁 递减地址(即,与完成 其构造;见12.6.2)

鉴于这是标准强制的行为,您需要声明和定义析构函数

定义,即使是空的,也需要告诉链接器在对象被删除的情况下跳转到哪里(或者它什么也做不了)


因此,总之,您需要自己声明和定义析构函数,不依赖于自动创建的默认析构函数(甚至不声明它),或者声明它并将其标记为默认析构函数。(假设编译器确实定义了它,但它应该有一个默认的实现)。

我只能想到一个可能出现问题的场景。这就是当您声明析构函数但不定义它时:

struct X { ~X(); };

int main() {
  std::unique_ptr<X> p(new X); 
}
现在,一切正常


请注意,如果析构函数被删除(手动删除或由编译器删除,例如,通过从非析构函数基派生),则会出现编译时错误,而不是链接时错误:


您可以将其声明为default~MyType()=default谢谢,我的意思是我根本不想要这个定义。但这是一种进步。那么“~MyType()=delete;”呢?如果我不需要析构函数,那就更好了。如果你想要一个类的实例,就不能没有析构函数。它是如何被销毁的?我个人认为,如果你没有声明一个析构函数的定义,那就更让人困惑了。如果删除析构函数,就永远无法创建该类的实例。啊哈,我对声明没有问题,但在有问题的编译单元中,我不能使用“=default;”,因为声明是共享的,而定义在另一个编译单元中不是微不足道的。
// In a seperate unit where the destructor is defined, you still
// have to use the `MyUniquePtr` type for the virtual functions,
// but need a deleter which actually deletes the pointer.
// That's what `MyTypeDeleter` is.

MyType::~MyType() { }

void MyTypeDeleter(const MyType* p) noexcept {
    delete p;
}

MyUniquePtr pass_through2(MyUniquePtr instance) {
    if (!instance) {
        instance = MyUniquePtr(new MyType(/*arguments*/), MyTypeDeleter);
    }
    instance->something();
    return instance;
}
template<typename T>
class unique_ptr {
private:
    T* _ptr;
public:
    unique_ptr(T& t) {
       _ptr = &t;
    }
    unique_ptr(unique_ptr<T>&& uptr) {
       _ptr = std::move(uptr._ptr);
       uptr._ptr = nullptr;
    }
    ~unique_ptr() {
       delete _ptr;
    }
    unique_ptr<T>& operator=(unique_ptr<T>&& uptr) {
       if (this == uptr) return *this;
       _ptr = std::move(uptr._ptr);
       uptr._ptr = nullptr;
       return *this;
    }

    unique_ptr(const unique_ptr<T>& uptr) = delete;
    unique_ptr<T>& operator=(const unique_ptr<T>& uptr) = delete;
};
struct X { ~X(); };

int main() {
  std::unique_ptr<X> p(new X); 
}
struct X { };
struct X { ~X() = delete; };