应该允许std :: unique_ptr <void> </void>

时间:2013-11-07 16:12:57

标签: c++ visual-studio-2010 gcc c++11 unique-ptr

这是一个非常简单的问题。请考虑以下代码:

#include <iostream>
#include <memory>

typedef std::unique_ptr<void> UniqueVoidPtr;

int main() {
    UniqueVoidPtr p(new int);
    return 0;
}

使用以下命令g++ -std=c++0x -o prog file.cpp使用cygwin(g ++ 4.5.3)进行编译就可以了。但是,使用Microsoft编译器(VS 2010或2013)进行编译时出现此错误:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\memory(2067) : error C2070: 'void': illegal sizeof operand
        C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\memory(2066) : while compiling class template member function 'void std::default_delete<_Ty>::operator ()(_Ty *) const'
        with
        [
            _Ty=void
        ]
        C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\type_traits(650) : see reference to class template instantiation 'std::default_delete<_Ty>' being compiled
        with
        [
            _Ty=void
        ]
        C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\memory(2193) : see reference to class template instantiation 'std::tr1::is_empty<_Ty>' being compiled
        with
        [
            _Ty=std::default_delete<void>
        ]
        foo1.cpp(7) : see reference to class template instantiation 'std::unique_ptr<_Ty>' being compiled
        with
        [
            _Ty=void
        ]

这是预期的吗?我正在编写一个类,我希望在类中有一个唯一的指针。在尝试计算类的移动构造函数的语义时,我遇到了这个(我假设因为我最终得到了正确的移动构造函数编码:即其他错误已修复)。

4 个答案:

答案 0 :(得分:22)

GCC实际上有代码来阻止它,但它直到最近才起作用。

GCC的unique_ptrdefault_deleter::operator()中有一个静态断言,应该拒绝不完整的类型:

    static_assert(sizeof(_Tp)>0,
                  "can't delete pointer to incomplete type");

但是,作为扩展,GCC支持sizeof(void),因此断言不会失败,并且因为它出现在系统头中甚至不会发出警告(除非您使用-Wsystem-headers)。

我最近自己发现了这个问题,所以要修复它我添加了10 days ago

    static_assert(!is_void<_Tp>::value,
                  "can't delete pointer to incomplete type");

因此,使用trunk上的最新代码,您的示例无法按照标准的要求进行编译。

答案 1 :(得分:21)

MSVC是对的,而GCC是错误的:

标准(3.9 / 5):

  

未完全定义的对象类型和void类型是不完整类型

标准(20.7.1.1.2 / 4):

  

如果T是不完整类型,则程序格式错误

答案 2 :(得分:7)

问题归结为:

void* p = new int;
delete p;

查看n3797 5.3.5删除,我认为由于类型不匹配,delete p是未定义的行为,因此编译器行为是可接受的,因为代码是错误的。

注意:这与shared_ptr<void>不同,因为它使用类型擦除来跟踪传入的指针的原始类型。

答案 3 :(得分:3)

不要删除void *的变量。

如果您想使用Win32 Handles之类的东西,请提供自定义删除器。

例如:

void HandleDeleter(HANDLE h)
{
    if (h) CloseHandle(h);
}

using UniHandle = unique_ptr<void, function<void(HANDLE)>>;

然后:

UniHandle ptr(..., HandleDeleter);