有没有一种方法可以将shared_ptr<void>转换为shared_ptr<T>?

21

我希望保留std::shared_ptr的智能行为。那么有没有一种方法可以将一个共享的空指针转换为另一种类型而不会影响引用计数?我不能获取原始指针并从中创建一个新的共享指针。


2
可能是 https://dev59.com/gmw15IYBdhLWcg3wJ4cR 的重复问题。 - Billy ONeal
@BillyONeal:不,void不是所有类型的基类。C++并不是那么纯粹的面向对象。 - MSalters
@MSalters:这就是为什么我写了评论而不是实际投票关闭(我不想单方面这样做) - Billy ONeal
2个回答

23

您可以使用rob mayoff答案中的指针转换,但要小心。在这里,不小心触发未定义行为是很容易的:

struct MyClass {};

void* rawPtr = new MyClass;
shared_ptr<void> exampleVoid(rawPtr); // Undefined behavior;
                                      // calls delete (void*)ptr;

shared_ptr<void> exampleVoidCons(new MyClass);
    // OK, calls shared_ptr<void>::shared_ptr<MyClass>(MyClass*) which
    // makes a deleter calling delete (MyClass*)ptr;

shared_ptr<MyClass> example(new MyClass); // OK, calls delete (MyClass*)ptr;

shared_ptr<void> castToVoid = static_pointer_cast<void>(example);
    // OK, shared_ptr's deleter is erased so this still calls delete (MyClass*)ptr;

通常情况下,这种未定义的行为会导致类型的析构函数不被调用。例如,参见 ideone 上的输出结果,注意放入 void* 中的版本从未打印出已被销毁。


请参见 C++11 5.3.5 [expr.delete]/3:

  

在第一种情况(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型必须是要删除的对象的动态类型的基类,并且静态类型必须有一个虚拟析构函数,否则行为是未定义的。

由于实际对象永远不会有动态类型为 void,而 void 也从不是任何动态类型的基类,因此 delete 一个 void* 就会触发未定义的行为。


这个答案的早期版本有一个错误的shared_ptr exampleVoid(new MyClass)部分,我已经纠正了。随意取消点赞来惩罚我口误 :P - Billy ONeal
1
如果提供更完整的答案,即使您犯了错误,也应该鼓励承认并修正错误。我们大多数人都在这里学习,这是过程的一部分。 - Shafik Yaghmour
1
我很生气,因为当我正要写一条评论指出错误的例子时,你删除了答案以供编辑。;-) - Steve Jessop
@Steve:我抢了你的风头,是吧? :) - Billy ONeal

23

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接