std::unique_ptr<void> 不被 GCC 4.9.0 接受

std::unique_ptr<void> not accepted by gcc 4.9.0

本文关键字:GCC 不被 接受 void ptr lt std unique gt      更新时间:2023-10-16

因此gcc 4.9.0实现了一个类型不是voidstatic_assert离子以正确符合标准。这很好,都是为了符合标准。

我有一个变体类型,将数据存储在std::unique_ptr<void>下,现在不起作用。简单的修复方法是将其更改为std::shared_ptr<void>,并立即编译。更好的修复方法是提供deleter函函数。

下面是修复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;
}

这是否会在某些多态类型中表现出未定义的行为?

如果您使用unique_ptr<void, void(*)(void*)>(new X(...), Deleter<X>),那么对于任何X都是正确的,因为删除器使用了正确的对象动态类型。

如果Base没有虚拟析构函数,或者Base子对象与包含它的Derived对象不在同一个地址,那么unique_ptr<void, void(*)(void*)>(new Derived(...), Deleter<Base>)将具有未定义的行为(对于多态和非多态类型)。

但是,您应该在两个地方都使用static_cast而不是reinterpret_cast。你应该选择在特定情况下使用最弱的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> };
  }