c++ - std::vector::push_back() 不能在 MSVC 上为具有已删除移动构造函数的对象编译

标签 c++ gcc visual-c++ push-back deleted-functions

我有一个带有已删除移动构造函数的类,当我尝试在 MSVC(v.15.8.7 Visual C++ 2017)中调用 std::vector::push_back() 时,我收到一条错误消息,提示我正在尝试访问已删除的移动构造函数。但是,如果我定义了移动构造函数,则代码会编译,但永远不会调用移动构造函数。两个版本都可以在 gcc (v. 5.4) 上按预期编译和运行。

这是一个简化的例子:

#include <iostream>
#include <vector>

struct A
{
public:
    A() { std::cout << "ctor-dflt" << std::endl; }
    A(const A&) { std::cout << "ctor-copy" << std::endl; }
    A& operator=(const A&) { std::cout << "asgn-copy" << std::endl; return *this; }
    A(A&&) = delete;
    A& operator=(A&& other) = delete;
    ~A() { std::cout << "dtor" << std::endl; }
};


int main()
{
    std::vector<A> v{};
    A a;
    v.push_back(a);
}

在 Visual Studio 上编译时会出现以下错误:

error C2280: 'A::A(A &&)': attempting to reference a deleted function  

如果我定义移动构造函数而不是删除它

 A(A&&) { std::cout << "ctor-move" << std::endl; }

一切都编译并运行,输出如下:

ctor-dflt
ctor-copy
dtor
dtor

正如预期的那样。不调用移动构造函数。 (直播代码:https://rextester.com/XWWA51341)

此外,这两个版本都可以在 gcc 上完美运行。 (直播代码:https://rextester.com/FMQERO10656)

所以我的问题是,为什么对不可移动对象的 std::vector::push_back() 调用不能在 MSVC 中编译,即使显然从未调用过移动构造函数?

最佳答案

这是未定义的行为,所以 gcc 和 MSVC 都是正确的。

我最近在推特上发布了一个类似案例 using std::vector::emplace_back with a type that has a deleted move constructor就像这个一样,它是未定义的行为。所以这里所有的编译器都是正确的,未定义的行为不需要诊断,尽管实现可以自由地这样做。

我们可以从 [container.requirements.general] Table 88 开始了解其中的原因。这告诉我们 push_back 要求 TCopyInsertable:

Requires: T shall be CopyInsertable into x

我们可以看到 CopyInsertable 需要 MoveInsertable [container.requirements#general]p15 :

T is CopyInsertable into X means that, in addition to T being MoveInsertable into X...

在这种情况下,A 不是 MoveInsertable

我们可以通过查看 [res.on.required]p1 看到这是未定义的行为。 :

Violation of the preconditions specified in a function's Requires: paragraph results in undefined behavior unless the function's Throws: paragraph specifies throwing an exception when the precondition is violated.

[res.on.required] 属于 Library-wide requirements .

在这种情况下,我们没有 throws 段落,因此我们有未定义的行为,这不需要诊断,正如我们从它的 definition 中看到的那样:

behavior for which this International Standard imposes no requirements....

注意,这与需要诊断的格式错误非常不同,我在 my answer here 中解释了所有细节.

关于c++ - std::vector::push_back() 不能在 MSVC 上为具有已删除移动构造函数的对象编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52945648/

相关文章:

c++ - 定义带有 void* 参数的纯虚函数的抽象基类。派生类匹配参数是指向某种类型的指针

linux - lcov - 在运行时创建和使用 gcad 文件

linux - 如何编译 Linux 应用程序以在共享 Web 服务器上运行

c++ - 尝试从 Visual Studios C++ 中的加密字符串输出解密字符串时出现逻辑错误

c++ - 如何将 IStream 实例中的数据读入 char 指针?

visual-c++ - MS Visual Studio 10上的OpenCV:cv::cvtColor导致找不到入口点错误消息

c++ - 我的头文件和 C++ 实现文件有问题

c++ - 是否有任何 std::set 实现不使用红黑树?

c++ - 我如何在 QT 中将 SSL 证书添加到我的代码中

c++ - 如何使用 g++ 创建静态库?