有效地初始化const std :: vector类成员

时间:2018-08-09 11:19:53

标签: c++ performance c++11 vector constructor

让我们假设我正在尝试创建“不可变的”类对象(即,成员变量是用const定义的)。因此,当调用构造函数时,我当前调用单独的init函数来初始化类成员。但是结果是似乎出现了许多新的向量创建和向量复制。

如果成员不是const,则可以在构造函数的{ }部分中执行初始化,然后直接写入values(我认为这样会更有效)。但这是不可能的。

有没有更好/更干净/更有效的方法来设计不可变类的构造?

#include <vector>

class Data
{
public:
    const std::vector<int> values;

    Data(unsigned int size, int other) : values(init(size, other)) { }
    Data(const std::vector<int>& other) : values(init(other)) { }

private:
    std::vector<int> init(unsigned int size, int other) {
        std::vector<int> myVector(size);

        for (unsigned int i = 0; i < size; ++i)
            myVector[i] = other * i;

        return myVector;
    }

    std::vector<int> init(const std::vector<int>& other) {
        std::vector<int> myVector(other);

        for (unsigned int i = 0; i < other.size(); ++i)
            myVector[i] *= myVector[i] - 1;

        return myVector;
    }
};

int main() {
    Data myData1(5, 3);         // gives {0, 3, 6, 9, 12}
    Data myData2({2, 5, 9});    // gives {2, 20, 72}

    return 0;
}

3 个答案:

答案 0 :(得分:2)

您当前的设计非常好。初始化发生在构造函数的成员初始化列表中,因此它将在最坏的情况下触发移动(无论如何对于矢量来说这都是相当便宜的),而在最佳情况下会触发 NRVO

NRVO 命名返回值优化 。当函数返回具有自动存储持续时间的命名变量时,允许编译器取消复制/移动。但是请注意,即使在省略的情况下,复制/移动构造函数仍然需要可用。这是一个概括这个概念的虚拟示例:

SomeType foo() { // Return by value, no ref
    SomeType some_var = ...; // some_var is a named variable
                             // with automatic storage duration
    do_stuff_with(var);
    return some_var; // NRVO can happen
}

(您的init函数遵循该模式。)

在C ++ 17中,根据init函数的形状,您甚至可以从这种情况下受益于保证的复制省略。您可以在其他enter image description here中找到有关此内容的更多信息。

注意:由于您标记了问题SO answer,因此我认为移动语义可用。

答案 1 :(得分:1)

你说

  

似乎有很多新的向量创建和向量复制正在进行。

但是我不确定。相反,我希望在这里进行一次完整的创作,然后采取以下行动: init生成并返回一个临时向量(可以创建完整的向量,直接使用最终大小),该向量用于初始化const成员(可以在此处进行移动)。我们应该在这里控制生成的程序集,但是一个不错的编译器应该一次构建数据块,然后将其移动到数据成员中。

因此,除非您可以通过概要分析(或通过查看编译器生成的程序集)证明确实需要在此处进行优化,否则我将很高兴继续使用此代码,因为它清楚地声明了成员常量。

答案 2 :(得分:0)

这里的解决方案是从成员向量中删除const,以便您可以就地执行初始化,而不是通过复制来完成。

如果您希望values可以被该类的用户阅读但不能写,则可以公开对其的const引用:

class Data {
    std::vector<int> values_;

    // constructors...

public:
    std::vector<int> const& values() const { return values_; }
};