C++ 我可以解决独特的问题吗\u ptr<;MyType>;仅存储nullptr时是否不需要MyType析构函数定义?
我需要使用VS2012编译器并具有: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
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; };