C++ 为什么带有auto_ptr和显式析构函数的结构无法交换

C++ 为什么带有auto_ptr和显式析构函数的结构无法交换,c++,visual-studio,C++,Visual Studio,看看这个代码。测试结构有一个自动ptr和显式析构函数。当我在Windows环境(Visual Studio 2017 professional)中生成此代码时,出现错误级别为4的警告 警告C4239:使用了非标准扩展:“参数”:从“Test”转换为“Test&” 注意:非常量引用只能绑定到左值;复制构造函数引用非常量 我的理解是std::swap接受Test类的引用,并且无法将实例强制转换为引用。如果我移除析构函数或auto_ptr警告将消失。知道原因是什么吗 #include <algo

看看这个代码。测试结构有一个自动ptr和显式析构函数。当我在Windows环境(Visual Studio 2017 professional)中生成此代码时,出现错误级别为4的警告

警告C4239:使用了非标准扩展:“参数”:从“Test”转换为“Test&”
注意:非常量引用只能绑定到左值;复制构造函数引用非常量

我的理解是
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]);
}
#包括
#包括
类型定义结构测试
{
公众:
INTA;
std::自动ptr b;
~Test()
{
}
}试验类型;
int main()
{
试验类型arr[2];
arr[0].a=5;
arr[1].a=3;
标准::交换(arr[0],arr[1]);
}

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

这迫使
Test
隐式声明的复制构造函数也通过非
const
引用获取源代码

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

因此,在
交换的内部,当它执行与
测试类型tmp=std::move(arr[0])等效的操作时,唯一可用的构造函数是采用非常量引用的复制构造函数,而可以使用该构造函数的唯一原因是警告中提到的非标准扩展,允许此类引用绑定到右值

取出
auto_ptr
Test
隐式声明的构造函数现在将获取一个
const
引用,该引用将绑定到右值

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

请注意,
Test
的move构造函数不应隐式定义为deleted,这可能令人惊讶。虽然
auto_ptr
没有移动构造函数,但测试是从右值
auto_ptr
直接初始化重载解析是否成功。多亏了
auto_ptr_ref
的诡计,它做到了。Clang和GCC都搞错了,而MSVC搞错了(!)


以上所有内容也适用于分配操作员。

我们谈论的是哪个MSVC版本?2017专业版。这是微软的解释,尽管我不知道如何匹配我的场景。出于好奇-为什么
auto\u ptr
?@Nim:这是一款传统产品。我刚刚将场景从一个大的代码集简化为这几行。如果将
unique\u ptr
替换为
auto\u ptr
,并显式声明析构函数,则行为是相同的。主要原因是,这将禁用所有隐式声明的构造函数/赋值运算符(请参见之前的规则三和现在的规则五),例如,对于
unique\u ptr
,这将失败,因为用户定义的析构函数阻止生成移动构造函数和移动赋值,从而阻止交换。如果您明确定义移动构造函数/赋值和
默认值
它们,那么这将使用
unique\u ptr
编译
auto_ptr
刚刚坏掉。感谢您的精彩解释,令人惊讶的是,Clang和GCC都错了,而MSVC做对了。顺便问一下,这种行为在标准中有定义吗?