应该允许std :: unique_ptr <void>

And*_*nga 24 c++ gcc visual-studio-2010 unique-ptr c++11

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

#include <iostream>
#include <memory>

typedef std::unique_ptr<void> UniqueVoidPtr;

int main() {
    UniqueVoidPtr p(new int);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用以下命令使用cygwin(g ++ 4.5.3)进行编译g++ -std=c++0x -o prog file.cpp就可以了.但是,使用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
        ]
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*ely 22

GCC实际上有防止它的代码,但它直到最近才起作用.

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

    static_assert(sizeof(_Tp)>0,
                  "can't delete pointer to incomplete type");
Run Code Online (Sandbox Code Playgroud)

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

我最近自己发现了这个问题所以要修复它我在10天前添加了这个:

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

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


ixS*_*Sci 21

MSVC是对的,而GCC错了:

标准(3.9/5):

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

标准(20.7.1.1.2/4):

如果T是不完整类型,则程序格式不正确

  • +1这种行为是不正确的而不是未定义的,是'unique_ptr`的故意设计目标.使用不推荐的`auto_ptr`做同样的事情是未定义的行为.差异很大,形成不良需要诊断.未定义的行为可以无声地执行任何操作.所有这一切,如果你的`custom_deleter`可以处理`void*`的处理,`unique_ptr <void,custom_deleter>`是完全有效的. (21认同)

Nev*_*vin 7

问题归结为:

void* p = new int;
delete p;
Run Code Online (Sandbox Code Playgroud)

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

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

  • 你说你上面的代码片段会产生UB是对的.但是,如果指向的类型不完整,则`default_delete`不应调用`delete`,否则程序格式不正确(参见ixSci的答案). (3认同)
  • @ixSci看一下实现?删除器是在原始指针类型上模板化的. (2认同)