【问题标题】:C++ copy, move constructorsC++ 复制、移动构造函数
【发布时间】:2018-12-14 14:03:27
【问题描述】:

我这里有代码:

#include <string>
#include <iostream>
#include <initializer_list>

template <typename T>
class Test
{
public:
  Test(std::initializer_list<T> l)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

  Test(const Test<T>& copy)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
  Test(Test&&) = delete;
  Test() = delete;
};

void f(const Test<Test<std::string>>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

void f(const Test<std::string>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
  f(Test<Test<std::string>>{x});
}

int main()
{
  Test<std::string> t1 {"lol"};
  f(t1);
  return 0;
}

我尝试在我的 linux mint 19 上使用 GCC 7.3.0 使用以下命令进行编译:

g++ -std=c++11 -O0 test.cpp -o test -Wall -pedantic

编译失败,错误提示:

f(Test<Test<std::string>>{x});

需要移动构造函数,但它已被删除。我一直认为移动和复制构造函数在编译方面是等价的,因为右值可以绑定到 const 引用,但是显式定义的右值引用的重载只是在重载决议中优先考虑。这是我第一次看到编译器实际上需要移动构造函数并且不会只使用复制。为什么?我错过了什么吗?

【问题讨论】:

  • 一个deleted 函数被声明。它将在名称查找期间包含在重载集中,因此您实际上是在尝试调用 deleted 函数。如果您定义了一个复制构造函数并且根本没有声明一个移动构造函数,那么您将获得您所期望的行为。
  • @BoBTFish 在这种情况下,我的类将定义移动,因为编译器将为我生成它,我将拥有一个。使用 delete 我禁止编译器生成一个。
  • 如果您有一个用户定义的复制构造函数,这将禁止编译器提供移动构造函数。 See this table.

标签: c++ c++11 copy-constructor move-constructor


【解决方案1】:

您显式声明了移动构造函数并将其标记为delete,它将被重载决议选中,然后导致错误。

如果同时提供了复制和移动构造函数并且没有其他构造函数是可行的,如果参数是相同类型的右值(一个 xvalue,例如 std::move or a prvalue such as a nameless temporary (until C++17) 的结果),重载决策将选择移动构造函数, 如果参数是左值(命名对象或返回左值引用的函数/运算符),则选择复制构造函数。

注意deleted implicitly-declared move constructor 被重载决议忽略,但显式声明的则不会。

重载决议忽略已删除的隐式声明的移动构造函数(否则它会阻止从右值进行复制初始化)。 (C++14 起)

【讨论】:

    【解决方案2】:

    我一直认为移动和复制构造函数在编译方面是等价的,因为右值可以绑定到 const 引用,但是在重载决议中,具有显式定义的右值引用的重载只是优先考虑。

    你的这个假设是正确的。如果您有一个采用const&amp; 和&amp;&amp; 的重载集,则如果您有右值,则&amp;&amp; 版本将优先于const&amp;。这里的问题是您的&amp;&amp; 版本被标记为已删除。这意味着您明确声明您不想从临时构建,代码将无法编译。

    在这种情况下,如果你不希望类是可移动的,那么你可以摆脱

    Test(Test&&) = delete;
    

    由于你的用户定义的拷贝构造函数的存在会移除编译器自动生成的移动构造函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-12
      • 2022-11-21
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 2017-06-11
      • 2023-03-20
      • 2023-03-28
      相关资源
      最近更新 更多