3

为什么 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 的类(和其他可移动类)都应该有一个显式的移动构造函数和赋值?

4

4 回答 4

9

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

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

如果类 X 的定义没有显式声明移动构造函数,当且仅当

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

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

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

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

同样对于复制赋值运算符:

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

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

  1. 复制构造函数
  2. 复制作业
  3. 移动构造函数
  4. 移动作业
  5. 析构函数
于 2011-05-12T11:32:40.467 回答
7

使用完全符合 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;
    }

};
于 2011-05-12T10:50:46.487 回答
2

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

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

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

于 2011-05-12T09:55:08.880 回答
1

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

于 2011-05-12T10:06:01.723 回答