这是一个非常简单的问题。请考虑以下代码:
#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
]
这是预期的吗?我正在编写一个类,我希望在类中有一个唯一的指针。在尝试计算类的移动构造函数的语义时,我遇到了这个(我假设因为我最终得到了正确的移动构造函数编码:即其他错误已修复)。
答案 0 :(得分:22)
GCC实际上有代码来阻止它,但它直到最近才起作用。
GCC的unique_ptr
在default_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);