c++ - 为什么 struct with auto_ptr 和显式析构函数无法交换

标签 c++ visual-studio

看看这段代码。测试结构有一个 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_ptrTest 的隐式声明的构造函数现在将采用 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/

相关文章:

visual-studio - MSI - 不需要应用程序关闭

c++ - CMake - visual studio 2008 的 fatal error

c++ - 没有匹配函数来调用 'meetings::meetings()

c# - 从 C# 而不是 C++ 调用时,非托管库函数失败

c++ - 只有三分之一的图像是用 OpenCV 编写的

c++ - 从 ‘const char*’ 到 ‘char’ 的无效转换

visual-studio - CMAKE : how to link executable to winmm imm32 version on windows with Visual Studio?

c++ - 引用宏的扩展值

xml - Visual Studio 中是否有键盘快捷键可以跳转到 XML 代码 View 中的父 XML/XHTML 节点?

visual-studio - 每当测试断言时 VSTest 磁盘驱动器错误