为什么使用auto_ptr和显式析构函数的struct无法交换

时间:2017-05-26 06:22:26

标签: c++ visual-studio

看看这段代码。 Test struct有一个auto_ptr和显式析构函数。当我在Windows环境(Visual Studio 2017专业版)中使用错误级别4 构建此代码时,它会显示此警告。

warning C4239: nonstandard extension used: 'argument': conversion from 'Test' to 'Test &' note: A non-const reference may only be bound to an lvalue; copy constructor takes a reference to non-const

我理解的是std::swap接受Test类的引用,并且无法将实例转换为引用。如果我删除析构函数或auto_ptr警告消失。不知道是什么原因?

#include <algorithm>
#include <memory>
typedef struct Test
{
public:
    int a;
    std::auto_ptr<Test> b;
    ~Test()
    {
    }
} Test_Type;


int main()
{
    Test_Type arr[2];
    arr[0].a = 5;
    arr[1].a = 3;
    std::swap(arr[0], arr[1]);
}

1 个答案:

答案 0 :(得分:2)

auto_ptr很奇怪,因为它的“复制”构造函数通过非const引用获取源代码,因为它需要修改它。

强制Test隐式声明的复制构造函数也通过非const引用来获取源。

用户声明的析构函数禁止移动构造函数的隐式声明。

因此在swap内部,当它相当于Test_Type tmp = std::move(arr[0]);时,唯一可用的构造函数是采用非const引用的复制构造函数,构造函数甚至可以使用的唯一原因是警告中提到的非标准扩展,允许这样的引用绑定到右值。

取出auto_ptrTest隐式声明的构造函数现在将引用const引用,该引用会绑定到rvalues。

取出析构函数,Test现在将有一个隐式声明的移动构造函数,可以用于移动。

请注意,Test的移动构造函数可能不会被隐含地定义为已删除。虽然auto_ptr没有移动构造函数,但测试的是从右值auto_ptr进行直接初始化的重载解析是否成功。它确实,感谢auto_ptr_ref恶作剧。 Clang和GCC都错了,而MSVC却做对了(!)。

以上所有内容也适用于赋值运算符。