为什么shared_ptr< void>合法,而unique_ptr< void>格式不正确? [英] Why is shared_ptr<void> legal, while unique_ptr<void> is ill-formed?

查看:77
本文介绍了为什么shared_ptr< void>合法,而unique_ptr< void>格式不正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题确实适合标题:我很好奇,知道造成这种差异的技术原因是什么,还有原理?

The question really fits in the title: I am curious to know what is the technical reason for this difference, but also the rationale ?

std::shared_ptr<void> sharedToVoid; // legal;
std::unique_ptr<void> uniqueToVoid; // ill-formed;


推荐答案

这是因为 std: :shared_ptr 实现类型擦除,而 std :: unique_ptr 不实现。

It is because std::shared_ptr implements type-erasure, while std::unique_ptr does not.

由于 std :: shared_ptr 实现类型擦除,它还支持另一个有趣的属性,即。它确实不需要删除器的类型作为类模板的模板类型参数。查看他们的声明:

Since std::shared_ptr implements type-erasure, it also supports another interesting property, viz. it does not need the type of the deleter as template type argument to the class template. Look at their declarations:

template<class T,class Deleter = std::default_delete<T> > 
class unique_ptr;

其中以 Deleter 作为类型参数,而

which has Deleter as type parameter, while

template<class T> 
class shared_ptr;

没有它。

现在问题是,为什么 shared_ptr 实施类型擦除?好吧,之所以这样做,是因为它必须支持引用计数,并且要支持引用计数,它必须从堆中分配内存,并且由于无论如何它都必须分配内存,因此它又走了一步并实现了类型擦除—这也需要堆分配。因此,基本上它只是机会主义者!

Now the question is, why does shared_ptr implement type-erasure? Well, it does so, because it has to support reference-counting, and to support this, it has to allocate memory from heap and since it has to allocate memory anyway, it goes one step further and implements type-erasure — which needs heap allocation too. So basically it is just being opportunist!

由于类型擦除, std :: shared_ptr 能够支持两件事:

Because of type-erasure, std::shared_ptr is able to support two things:


  • 它可以存储任何类型的对象,例如 void * c em>然而,它仍然能够正确地销毁销毁对象,方法是正确调用销毁函数。

  • 删除器的类型未传递为类模板的类型实参,这意味着在不损害类型安全性的情况下有一点自由。

  • It can store objects of any type as void*, yet it is still able to delete the objects on destruction properly by correctly invoking their destructor.
  • The type of deleter is not passed as type argument to the class template, which means a little bit freedom without compromising type-safety.

好的。这就是 std :: shared_ptr 的工作原理。

Alright. That is all about how std::shared_ptr works.

现在的问题是, std :: unique_ptr 将对象存储为 void * ?嗯,答案是,—前提是您传递了合适的Deleter作为参数。这是一个这样的演示:

Now the question is, can std::unique_ptr store objects as void*? Well, the answer is, yes — provided you pass a suitable deleter as argument. Here is one such demonstration:

int main()
{
    auto deleter = [](void const * data ) {
        int const * p = static_cast<int const*>(data);
        std::cout << *p << " located at " << p <<  " is being deleted";
        delete p;
    };

    std::unique_ptr<void, decltype(deleter)> p(new int(959), deleter);

} //p will be deleted here, both p ;-)

输出(在线演示):

959 located at 0x18aec20 is being deleted






您在评论中问了一个非常有趣的问题:


You asked a very interesting question in the comment:


在我的情况下,我需要擦除类型deleter,但似乎也是可行的(以分配一些堆为代价)。基本上,这是否意味着实际上存在第三种类型的智能指针的利基点:具有类型擦除的专有所有权智能指针。

In my case I will need a type erasing deleter, but it seems possible as well (at the cost of some heap allocation). Basically, does this mean there is actually a niche spot for a 3rd type of smart pointer: an exclusive ownership smart pointer with type erasure.

@Steve Jessop 提出以下解决方案的地方,

to which @Steve Jessop suggested the following solution,

我从未真正尝试过此操作,但也许可以通过使用适当的 std :: function 作为删除器类型( unique_ptr ?假设实际可行,那么您就完成了,排他性所有权和类型删除的删除器。

I've never actually tried this, but maybe you could achieve that by using an appropriate std::function as the deleter type with unique_ptr? Supposing that actually works then you're done, exclusive ownership and a type-erased deleter.

根据此建议,我实现了这一点(尽管它似乎不需要使用 std :: function ):

Following this suggestion, I implemented this (though it does not make use of std::function as it does not seem necessary):

using unique_void_ptr = std::unique_ptr<void, void(*)(void const*)>;

template<typename T>
auto unique_void(T * ptr) -> unique_void_ptr
{
    return unique_void_ptr(ptr, [](void const * data) {
         T const * p = static_cast<T const*>(data);
         std::cout << "{" << *p << "} located at [" << p <<  "] is being deleted.\n";
         delete p;
    });
}

int main()
{
    auto p1 = unique_void(new int(959));
    auto p2 = unique_void(new double(595.5));
    auto p3 = unique_void(new std::string("Hello World"));
}  

输出(在线演示):

{Hello World} located at [0x2364c60] is being deleted.
{595.5} located at [0x2364c40] is being deleted.
{959} located at [0x2364c20] is being deleted.

希望有帮助。

这篇关于为什么shared_ptr&lt; void&gt;合法,而unique_ptr&lt; void&gt;格式不正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆