gpt4 book ai didi

c++ - 为什么 unique-ptr 不检查基类是否可虚拟破坏?

转载 作者:IT老高 更新时间:2023-10-28 22:27:29 25 4
gpt4 key购买 nike

考虑这个例子:

#include <cstdio>
#include <memory>

struct base
{
base( int i ): i(i) { printf("base ctor\n"); }
~base() { printf("base non-virtual dtor\n"); } // non-virtual
int i;
};

struct derived : public base
{
char* s;
derived(int i): base(i), s(new char[i] )
{
printf("derived ctor\n");
}
~derived()
{
printf("derived dtor\n");
delete [] s;
}
};

int main()
{
printf("Success\n");

//raw pointer
printf("RAW-POINTER\n");
{
base* b = new derived(2);
// ......
delete b; //here memory leak, but it's old- and error-prone code.
}
printf("---END-RAW-POINTER--\n");

//unique-ptr
printf("UNIQUE_PTR\n");
{
// I would that, this doesn't compile, because base- has not virtual destructor.
std::unique_ptr<base> bu( new derived(3) ); // here still memory leak !!!!
}
printf("--END-UNIQUE_PTR--\n");


return 0;
}

代码 std::unique_ptr<base> bu( new derived(3) );使用 std::has_virtual_destructor 轻松禁止类型特征。 Live code

那么为什么要编译上面的代码呢?这是标准允许的吗?

编辑:有趣,但 std::shared_ptr 有效,即基础和派生 dtor 都会调用:

    printf("SHARED_PTR\n");
{
std::shared_ptr<base> b(new derived(3));
}
printf("--END-SHARED_PTR--\n");

Output:
SHARED_PTR
base ctor
derived ctor
derived dtor
base non-virtual dtor
--END-SHARED_PTR--

为什么 std::shared_ptr 可以调用派生类 dtor,而 std::unique_ptr 不能???

EDIT2:简单我需要类似的东西:

template< typename T, typename D = default_deleter<T> >
class unique_ptr{
.............

template< typename U >
unique_ptr( U* u ) if ( U != T && T - is class && T is base of U, and D - is default_deleter, and T - has not virtual destructor ) then = delete this ctor.

};

最佳答案

unique_ptr 的区别和 shared_ptr就其析构函数(和构造函数)而言,采用标准语言。适用于您的示例的两个智能指针的删除器的语言相似但略有不同:

[20.7.1.2.2] unique_ptr destructor ... If get() ==  nullptr there are no efects. Otherwise get_deleter()(get()).[20.7.2.2.2] shared_ptr destructor... if *this owns an object p and a deleter d, d(p) is called.

You can see that in both cases the standard says to call the deleter, the difference though in how the deleter is decided on, and that unique_ptr deletes the pointer it obtains via get(), while shared_ptr deletes the object. This distinction is important. Look at how the constructors for both classes are also different:

The shared_ptr is defined as follows:

template <class  T> 
class shared_ptr {
...
template<class Y> explicit shared_ptr(Y* p);

虽然 unique_ptr显式单参数构造函数是,

template <class  T, class D = default_delete<T>>
class unique_ptr {
...
explicit unique_ptr(pointer p) noexcept;
...

注意 unique_ptr只是获取该类型的默认删除,即普通的 delete在您的情况下,并存储指针。但是,shared_ptr<T>构造函数未在 T 上进行模板化(!),它以对象的类型为模板 Y它是用它构建的。因此,在您的场景中,

std::shared_ptr<base> b(new derived(3));

shared_ptr将使用 T=base 构建但是 Y=derived ,允许显式销毁派生对象,并且在您的示例中不会泄漏内存。


虽然您无法更改标准,但您可以做的就是继承 unique_ptr在您的项目中,或提供您自己的包装器来强制执行所需的行为。例如,

namespace {
template <class T>
struct checked_delete : public std::default_delete<T> {
static_assert(std::has_virtual_destructor<T>::value, "");
};

template <class T, class D = checked_delete<T>, class U>
std::unique_ptr<T, D>
make_unique_ptr(U* p) { return std::unique_ptr<T, D>(p, D()); }
}

// now this won't compile, because checked_delete<base> will not compile:
auto bu = make_unique_ptr<base>(new derived(3));

关于c++ - 为什么 unique-ptr 不检查基类是否可虚拟破坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22124981/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com