将std::vector v传递给类的ctor,该类需要在相应实例的整个生命周期内访问v

Pass a std::vector v to the ctor of a class which needs to access v during the whole life time of a corresponding instance

本文关键字:实例 生命 访问 周期 vector std ctor      更新时间:2023-10-16

我想将std::vector<double> v传递给类A的构造函数,该构造函数需要在相应实例的整个生命周期内访问v。由于v被认为是巨大的,所以我不想复制v

我们可以做以下操作:选项1

class A
{
public:
    A(std::vector<double> const& v)
        : m_v(v)
    { }
private:
    std::vector<double> const& m_v
};

如果我们可以保证引用的v对象的生存时间至少与A的相应实例的生存时间一样长,那么这可能是一个合适的选项。但我们不太可能保证这一点。

选项2:

class A
{
public:
    A(std::shared_ptr<std::vector<double>> v)
        : m_v(v)
    { }
private:
    std::shared_ptr<std::vector<double>> m_v;
};

此选项没有生命周期问题。然而,我不确定这是否真的是最佳实践。那么,我们应该怎么做呢?

  • 如果您不能保证引用的v对象的生存时间至少与A的相应实例的生存时间一样长,

  • 如果你不想复制v

那么CCD_ 11是要走的路。它被认为是的最佳实践。

例如,参见Herb Sutter 的《91周大师》

注意:shared_ptr会延长v的寿命,而weak_ptr不会——在A的生命中,你可能会失去v(以安全的方式(。您是否需要其中一个取决于您的用例。

如果向量必须在A实例的整个生命周期内保持活动,我会选择选项2,否则我会考虑std::weak_ptr<std::vector<双>gt;

如果我们可以保证引用的v对象的生存时间至少与a的相应实例的生存时间一样长,这可能是一个合适的选项。但我们不太可能保证这一点

(强调我的(表明在设计上还有更多的工作要做。要么你的类控制向量的生存期,要么它依赖于它。它是哪个?这一点在任何文档和界面描述中都应该清楚。

如果您规定A取决于可用的矢量,则可以在接口中要求:

A::A(const std::vector<double>& v)  // Demand that v outlives A
: _v(v) {}

如果您规定A将与其他对象共享矢量,然后在接口中要求:

A::A(std::shared_ptr<const std::vector<double>> pv) // demand shared ownswership
: _pv(std::move(pv)) {}

如果您规定A将实际控制矢量的寿命(然后拥有它(,则move将矢量放入其中,或者move将unique_ptr放入A:

// call with auto a = A(std::move(v));
// or auto a = A(std::vector<double>(...));
A::A(std::vector<double> v)  // demand ownership or copy
: _v(std::move(v)) {}
// or
A::A(std::unique_ptr<const std::vector<double>> pv) // demand ownership
: _pv(std::move(pv)) {}

"最佳实践"的一部分是使用接口定义为客户提供保证并提出要求。

然而,我不确定这是否真的是最佳实践。那么,我们应该怎么做呢?

auto make_huge_vector()
{
    return std::make_shared<std::vector<double>>( /* ... */ );
}

当前最佳实践(如果需要,强制延长矢量的使用寿命(:

class A
{
public:
    A(std::shared_ptr<std::vector<double>> v): v_{ std::move(v) } {}
private:
    std::shared_ptr<std::vector<double>> v_;
};
// client code:
auto v = make_huge_vector();
A a{v};