繁体   English   中英

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

[英]How to enable move semantics when adding custom objects to a vector?

下面的代码将包含大向量的对象传递给向量。 我希望这是高效的。 我是否需要在调用push_backtest为rvalue? 我是否需要告诉编译器如何移动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;
}

我希望这是高效的

以下应该足够好了。 我希望这些评论能帮助您理解代码。

#include <vector>
#include <iostream>
#include <numeric>

struct Test
{
    std::vector<size_t> vals;
    double sum = 0; // initialing is a good idea
    Test(const size_t v, const double res) // provide constructor(appropriate one)
        : vals(v), // tell the size of the vals directly in the constructor
          sum(res) 
    {}
};

int main()
{

    std::vector<Test> vecOfTest;
    vecOfTest.reserve(100000);

    for (size_t i = 0; i < 100000; i++)
    {
        // Test& last_test = vecOfTest.emplace_back() needs C++17, otherwise
        // use std::vector::back()
        auto& last_test = vecOfTest.emplace_back(   // create the Test object in place and take the reference to it
            i,                     // tell the size of vals in newly creating Test object
            ((i - 1) * i) / 2.0    // ((j-1) * j)/2 = sum from 0 to j-1
        );
        std::iota(std::begin(last_test.vals), std::end(last_test.vals), static_cast<size_t>(0)); // populate, 0 to size of vals
    }
    return 0;
}

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

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

    vecOfTest.push_back(test);
}

会做一个隐含的举动,因为范围结束,它不会。 隐式移动会使编译器和程序员陷入困境。 编译器需要证明无效test是正常的。 程序员将被要求不断调查是否需要显式移动,最终结果就是只做显式移动。 因此,由于这个原因,隐式移动不会发生(但请参阅下面的规则例外情况。)您需要自己完成:

vecOfTest.push_back(std::move(test));

你需要不移动的唯一情况是移动会干扰elision。 例如,在返回Test的函数中,这个:

Test test;
return std::move(test);

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

return test;

代替。 这不是一个隐含的举动。 这是一个省略。 Elision比移动更快,并且移动会阻止elision。 但是,在无法进行省略的情况下,则执行隐式移动。 这是我所知道的唯一一个隐含举动将会发生的情况:作为elision的替代品。 你原来的代码:

vecOfTest.push_back(test);

不是elision的情况,因此隐含的举动永远不会发生。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM