看看这段代码。测试结构有一个 auto_ptr 和显式析构函数。当我在 Windows 环境(Visual Studio 2017 专业版)错误级别 4 中构建此代码时,它会显示此警告。
警告 C4239:使用了非标准扩展:“argument”:从“Test”到“Test &”的转换
注意:非常量引用只能绑定(bind)到左值;复制构造函数引用非常量
我的理解是 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]);
}
最佳答案
auto_ptr
很奇怪,因为它的“复制”构造函数通过非常量引用获取源代码,因为它需要修改它。
这会强制 Test
的隐式声明的复制构造函数也通过非 const
引用获取源。
用户声明的析构函数会抑制移动构造函数的隐式声明。
因此在 swap
内部,当它执行与 Test_Type tmp = std::move(arr[0]);
等效的操作时,唯一可用的构造函数是拷贝构造函数采用非常量引用,甚至可以使用构造函数的唯一原因是警告中提到的非标准扩展,允许这样的引用绑定(bind)到右值。
去掉 auto_ptr
,Test
的隐式声明的构造函数现在将采用 const
引用,它确实绑定(bind)到右值。
去掉析构函数,Test
现在将有一个隐式声明的移动构造函数,可用于移动。
请注意,Test
的移动构造函数不应隐式定义为已删除,这也许令人惊讶。虽然 auto_ptr
没有移动构造函数,但测试是从右值 auto_ptr
直接初始化重载决议是否成功。确实如此,多亏了 auto_ptr_ref
恶作剧。 Clang 和 GCC 都做错了,而 MSVC 做对了(!)。
以上所有内容也适用于赋值运算符。
关于c++ - 为什么 struct with auto_ptr 和显式析构函数无法交换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44194933/