【问题标题】:Move constructor does not implicitly work for member variables?移动构造函数不会隐式地对成员变量起作用?
【发布时间】:2011-05-12 09:50:50
【问题描述】:

为什么 this: (vs2010) 不在类中移动向量?

#include <vector>

class MoveTest
{
public:
    std::vector<int> m_things;
};

int _tmain(int argc, _TCHAR* argv[])
{
    MoveTest m;
    m.m_things.push_back(12);

    MoveTest m2 = std::move(m);
    // std::vector has been copied, not moved

    return 0;
}

这是否意味着每个使用 std::vector 的类(和其他可移动类)都应该有一个显式的移动构造函数和赋值?

【问题讨论】:

    标签: c++11 move-constructor


    【解决方案1】:

    除了已经给出的关于这些规则与 vs2010 发布时相比延迟的好答案之外,

    隐式生成的移动构造函数的规则是:

    如果类 X 的定义确实 未明确声明移动 构造函数,一个将是隐式的 声明为默认当且仅当

    • X 没有用户声明的复制构造函数,
    • X 没有用户声明的复制赋值运算符,
    • X 没有用户声明的移动赋值运算符,
    • X 没有用户声明的析构函数,并且
    • 移动构造函数不会被隐式定义为已删除。

    隐式生成的移动赋值运算符的规则遵循上述模式。

    隐式生成复制构造函数的规则略有变化

    如果类定义没有 显式声明一个复制构造函数, 一个是隐式声明的。如果 类定义声明移动 构造函数或移动赋值 运算符,隐式声明的副本 构造函数被定义为删除; 否则定义为默认 (8.4)。后一种情况已弃用 如果该类具有用户声明的副本 赋值运算符或用户声明的 析构函数。

    对于复制赋值运算符也是如此:

    如果类定义没有 显式声明复制分配 运算符,一个是隐式声明的。 如果类定义声明了一个 移动构造函数或移动赋值 运算符,隐式声明的副本 赋值运算符定义为 已删除;否则,定义为 默认(8.4)。后一种情况是 如果该类有 用户声明的复制构造函数或 用户声明的析构函数。

    底线:3 的规则现在是 5 的规则。您可以忽略所有 5(如果默认行为适合您),或者您需要考虑(并可能定义)所有 5:

    1. 复制构造函数
    2. 复制分配
    3. 移动构造函数
    4. 移动作业
    5. 析构函数

    【讨论】:

      【解决方案2】:

      使用完全符合 C++0x 的编译器,您的类将具有用于移动成员的隐式移动构造函数,以及隐式复制构造函数。在本例中,因此将使用隐式移动构造函数。

      但是,MSVC2010 在这个规则被委员会同意之前就出来了,所以你必须明确地编写一个移动构造函数。然后,您还需要定义默认构造函数和复制构造函数,并且可能还应该定义移动赋值和复制赋值以更好地衡量:

      class MoveTest
      {
      public:
          std::vector<int> m_things;
      
          MoveTest()
          {}
      
          MoveTest(MoveTest&& other):
              m_things(std::move(other.m_things))
          {}
      
          MoveTest(MoveTest const& other):
              m_things(other.m_things)
          {}
      
          MoveTest& operator=(MoveTest&& other)
          {
              MoveTest temp(std::move(other));
              std::swap(*this,temp);
              return *this;
          }
      
          MoveTest& operator=(MoveTest const& other)
          {
              if(&other!=this)
              {
                  MoveTest temp(other);
                  std::swap(*this,temp);
              }
              return *this;
          }
      
      };
      

      【讨论】:

        【解决方案3】:

        MoveTest 类没有移动构造函数,因此它使用默认的复制构造函数。

        复制构造函数复制成员元素。 :-)

        在某些情况下,C++11 一致性编译器会生成默认的移动构造函数,但我不确定最终规则在哪里结束(有很晚的更改)。 VS2010 太旧了,也不知道。

        【讨论】:

          【解决方案4】:

          VS2010 没有隐式移动构造函数。你必须明确写一个。

          【讨论】:

            猜你喜欢
            • 2011-09-13
            • 2012-11-09
            • 1970-01-01
            • 2011-08-08
            • 1970-01-01
            • 2020-09-07
            • 2014-11-22
            • 2020-08-05
            • 2015-06-30
            相关资源
            最近更新 更多