有没有办法将 shared_ptr<void> 转换为 shared_ptr<T>?

Posted

技术标签:

【中文标题】有没有办法将 shared_ptr<void> 转换为 shared_ptr<T>?【英文标题】:Is there a way to cast shared_ptr<void> to shared_ptr<T>? 【发布时间】:2014-11-09 14:56:37 【问题描述】:

我想保持std::shared_ptr 的聪明行为。那么有没有办法在不混淆引用计数的情况下将共享的 void 指针转换为另一种类型?我无法获取原始指针并从中创建新的共享指针。

【问题讨论】:

***.com/questions/6795629/…的可能重复 @BillyONeal:不,void 不是所有类型的基类。 C++ 并不是那么纯粹的 OO。 @MSalters:这就是我写评论而不是实际投票结束的原因(我不想单方面这样做) 【参考方案1】:

您可以使用来自rob mayoff's answer 的指针转换;但小心点。这里很容易无意触发未定义的行为:

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;

通常这种未定义的行为会导致类型的析构函数不被调用。例如,see the output on ideone 并注意放入 void* 的版本永远不会显示它已被销毁。


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

在第一种选择(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为要删除的对象的动态类型的基类和静态类型的基类。类型应具有虚拟析构函数或行为未定义。

由于实际对象永远不会有动态类型void,而void 永远不是动态类型的基类,所以delete 使用void* 会触发未定义的行为。

【讨论】:

这个答案的早期版本有一个不正确的shared_ptr exampleVoid(new MyClass) 部分,我现在已经修复了。随意删除将我的脚放在嘴里的赞成票:P +1 用于提供更完整的答案,同时认识到您犯了错误,应鼓励承认并改正错误,我们大多数人都在这里学习,这是过程的一部分。 我很生气,因为您删除了编辑的答案,就像我在写关于不正确示例的评论一样;-) @Steve:我抢了你的风头是吗? :)【参考方案2】:

您可以使用std::static_pointer_caststd::dynamic_pointer_cast,具体取决于您想要的演员类型。

【讨论】:

以上是关于有没有办法将 shared_ptr<void> 转换为 shared_ptr<T>?的主要内容,如果未能解决你的问题,请参考以下文章

无法将参数 1 从 'std::shared_ptr<ChaseState>' 转换为 'std::shared_ptr<State<Cow>>

将(隐式)提升 shared_ptr<T> 转换为 shared_ptr<const T>

有没有办法避免隐式转换为 void*?

如何解释“void(*)()”?

有没有办法在 int 类型方法中返回 void

从 'B *' 到 'std::shared_ptr<A>' 的函数式转换没有匹配的转换