看看这段代码。 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]);
}
答案 0 :(得分:2)
auto_ptr
很奇怪,因为它的“复制”构造函数通过非const引用获取源代码,因为它需要修改它。
强制Test
隐式声明的复制构造函数也通过非const
引用来获取源。
用户声明的析构函数禁止移动构造函数的隐式声明。
因此在swap
内部,当它相当于Test_Type tmp = std::move(arr[0]);
时,唯一可用的构造函数是采用非const引用的复制构造函数,构造函数甚至可以使用的唯一原因是警告中提到的非标准扩展,允许这样的引用绑定到右值。
取出auto_ptr
,Test
隐式声明的构造函数现在将引用const
引用,该引用会绑定到rvalues。
取出析构函数,Test
现在将有一个隐式声明的移动构造函数,可以用于移动。
请注意,Test
的移动构造函数可能不会被隐含地定义为已删除。虽然auto_ptr
没有移动构造函数,但测试的是从右值auto_ptr
进行直接初始化的重载解析是否成功。它确实,感谢auto_ptr_ref
恶作剧。 Clang和GCC都错了,而MSVC却做对了(!)。
以上所有内容也适用于赋值运算符。