2014-05-06 49 views
3

所以gcc 4.9.0implemented a static_assert离子这个类型不是void要正确符合标准。这对于标准一致性来说很好。std :: unique_ptr <void>不被gcc所接受4.9.0

我有一个变种类型,存储在std::unique_ptr<void>现在不起作用的数据。简单的解决方法是将其更改为std::shared_ptr<void>,并立即编译。更好的解决办法是提供删除函子。

以下是修复unique_ptr的安全方法吗?这会显示未定义的行为与某些多态类型?

#include <memory> 
#include <iostream> 

template<typename T> 
void Deleter(void * p) { 
    delete reinterpret_cast<T*>(p); 
} 

int main() { 
    const std::unique_ptr<void, void(*)(void*)> v(new int(199), Deleter<int>); 
    std::cout << *reinterpret_cast<int*>(v.get()) << std::endl; 
    return 0; 
} 
+1

那岂不是更容易(从长远来看,反正)和比较安全[Boost variant](http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html)或[Boost any](http://www.boost.org/doc/libs/1_55_0) /doc/html/any.html)? –

+0

为什么不使用适当的变体类型(如[boost :: variant'](http://www.boost.org/doc/libs/release/doc/html/variant.html)或您自己的实现)?应尽可能少地使用'void *'。 –

+0

我有我自己的变体类型,这就是我已经实现的。我通常会使用增强变体,但我的变体需要可序列化。从'MurmurHash3'派生的类型标识号和序列化函数被删除。这使得我的当前用例所需的变量可以跨过进程/设备进行编组。 –

回答

9

将这个展览不确定某些态类型的行为呢?

如果使用unique_ptr<void, void(*)(void*)>(new X(...), Deleter<X>)这将是任何X正确的,因为缺失者使用正确的动态类型的对象。

如果您使用unique_ptr<void, void(*)(void*)>(new Derived(...), Deleter<Base>)将有不确定的操作(适用于多态和非多态类型),如果Base没有虚析构函数,或者如果Base子对象不是在同一地址为Derived对象包含它。

但是,您应该在两个地方都使用static_cast而不是reinterpret_cast。你应该更喜欢使用最弱的演员阵营,在一个特定的情况下,reinterpret_cast是一个大锤。

为了使代码更不容易出错我会写一个辅助函数,所以你永远只能命名类型一次,是这样的:

template<typename T, typename... Args> 
    std::unique_ptr<void, void(*)(void*)> 
    make_unique_void_ptr(Args&&... args) 
    { 
    using Ptr = std::unique_ptr<void, void(*)(void*)>; 
    return Ptr{ new T(std::forward<Args>(args)...), Deleter<T> }; 
    } 
+0

我正在使用你的第一个例子。谢谢你的回答(一如既往)。 –

+1

我相信第二种情况总是未定义的行为,即使'Base'有一个虚拟析构函数,仅仅是因为你不能指望'Derived *' - >'void *' - >'Base *不能保证'(void *)派生==(void *)base'通常(即使使用gcc,如果这是它的第一个基础)。 –

+1

@MatthieuM。好点,但这并不意味着它是_always_ UB,只有当'(void *)派生!=(void *)base'的时候。 –

相关问题