在向矢量添加自定义对象时如何启用移动语义?

wil*_*lem 5 c++ move-semantics c++11

下面的代码将包含大向量的对象传递到向量中。我希望它表现出色。我需要test在对的调用中强制转换为rvalue push_back吗?我需要告诉编译器如何移动struct实例Test吗?还是全部自动进行?

int main()
{
    struct Test
    {
        std::vector<size_t> vals;
        double sum;
    };
    std::vector<Test> vecOfTest;
    vecOfTest.reserve(100000);

    for (size_t i = 0; i < 100000; i++)
    {
        Test test{};
        test.vals.reserve(i);
        for (size_t j = 0; j < i; j++)
        {
            test.vals.push_back(j);
            test.sum += j;
        }
        vecOfTest.push_back(test);
    }


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Nik*_* C. 3

您的Test结构体没有定义任何特殊的成员函数(复制构造函数、析构函数等),这意味着会自动生成默认的移动赋值运算符和默认的移动复制构造函数,它们将移动结构体的每个数据成员。Test可移动类型也是如此,并且它从中受益,因为它vector<size_t>是可移动数据成员。

但是,移动不会自动执行,因为从对象移动会改变它。即使你会认为:

    vecOfTest.push_back(test);
}
Run Code Online (Sandbox Code Playgroud)

会执行隐式移动,因为范围结束,但不会。隐式的移动会让编译器和程序员陷入困境。编译器需要证明无效test是可以的。程序员需要不断地调查是否需要显式移动,而最终结果就是无论如何都只进行显式移动。因此,出于这个原因,隐式移动不会发生(但请参阅下面的规则例外情况。)您需要自己执行此操作:

vecOfTest.push_back(std::move(test));
Run Code Online (Sandbox Code Playgroud)

唯一不需要移动的情况是移动会干扰省略。例如,在返回 a 的函数中Test,如下:

Test test;
return std::move(test);
Run Code Online (Sandbox Code Playgroud)

会动,但最好不要动。最好是:

return test;
Run Code Online (Sandbox Code Playgroud)

反而。这并不是一个隐性的举动。这是一个省略。省略比移动更快,并且移动可以防止省略。然而,在无法省略的情况下,则会执行隐式移动。这是我所知道的唯一会发生隐式移动的情况:作为省略的替代。你原来的代码:

vecOfTest.push_back(test);
Run Code Online (Sandbox Code Playgroud)

不是省略的情况,因此隐式移动永远不会发生。