将unique_ptr的向量传递给对象.向量成为成员变量.正确的方法

Passing a vector of unique_ptr to an object. the vector becomes a member variable. correct approach?

本文关键字:向量 成员 变量 方法 unique ptr 对象      更新时间:2023-10-16

我将称之为"所有者"的一个对象,在其生命周期内拥有数据对象向量的明确所有权。

这些被存储为unique_ptr的向量。

一个名为"Output"的对象/类需要用许多不同的方法查看这些数据对象,因此某种引用/指针/变量是"Output"成员变量。

输出在其构造函数中接收数据对象的矢量。

我想了三种方法来实现这一点。什么是最好的方式?

选项1-"输出"对象将数据向量存储为常量引用:

class Output {
    // output wants the data:
 public:
    Output(std::vector<std::unique_ptr<Data>> const & in)
        : my_lot_of_data(in) {
    };
    std::vector<std::unique_ptr<Data>> const & my_lot_of_data;
}

由"所有者"用实例化

 data_vec_.push_back(std::unique_ptr<Data>(new Data));
 /* stuff happens to data */
 Output output(data_vec_);

选项2-"输出"对象将数据向量存储为常量指针:

class Output {
    // output wants the data:
 public:
    Output(std::vector<std::unique_ptr<Data>> const * in)
        : my_lot_of_data(in) {
    };
    std::vector<std::unique_ptr<Data>> const * my_lot_of_data;
}

由"所有者"用实例化

 data_vec_.push_back(std::unique_ptr<Data>(new Data));
 /* stuff happens to data */
 Output output(&data_vec_);

选项3-"输出"对象接收原始指针:

class Output {
    // output wants the data:
 public:
    Output(std::vector<Data*> in)
        : my_lot_of_data(in) {
    };
    std::vector<Data*> const my_lot_of_data;
};

由"所有者"用实例化

 data_vec_.push_back(std::unique_ptr<Data>(new Data));
 /* stuff happens to data */
 std::vector<Data*> data_as_raw;
 data_as_raw.resize(data_vec_.size());
 std::transform(data_vec_.begin(), data_vec_.end(), data_as_raw.begin(), [](std::unique_ptr<Data> const & x) {return x.get();});
 Output output(data_as_raw);

其他查询:在选项1和2中,是否清楚Output没有数据的所有权,即使它存储为unique_ptrs?选项3是否会在呼叫现场造成混乱?要达到同样的结果,还需要3行。

这里的最佳实践是什么?

如果你只需要"读取一些值,然后[创建]各种输出文件",我只需要让它成为一个通过const-ref:

void output(std::vector<std::unique_ptr<Data>> const& data) {
    // stuff
}

在用法语义上,我更喜欢const&而不是const*data[0](*data)[0]),而且肯定更喜欢两者都传递原始数据-不要白白放弃显式所有权(在这种情况下,这甚至不是为了方便,因为无论如何构造vector<Data*>都很烦人)

由于您使用的是unique_ptr,您不打算与任何可能比Owner持续时间更长的数据共享此数据,因此简单的const引用应该很好。我推荐一个不错的typedef:

typedef std::vector<std::unique_ptr<Data>> OwnerDataSet;
Output(const OwnerDataSet &in)

方法1的优点是它简单明了。其他人只是莫名其妙地把事情弄复杂了。

unique_ptr的功能是在std::vector被破坏时删除新的Data。这里的替代方案是复制Data的实例,而不是调用new。如果你不需要使用指针,那么你就不需要像unique_ptr这样的特殊处理来保证它们的安全。

typedef std::vector<Data> OwnerDataSet;
OwnerDataSet results;
Data match = findoneresult();
results.push_back(match); // copy something from Owner
Output (results);

更进一步,从您的示例中还不清楚为什么要在Output类之外维护std::vector。由于您在传递的所有内容上都调用std::unique_ptr(new T),我怀疑您只在Output中使用它,所以您可以这样做:

class Output : public std::vector<Data> {
    void PrintToScreen();
    void WriteToDatabase();
    void OrWhatever();
};
Output x;
Data match = findoneresult();
x.push_back(findoneresult());
x.PrintToScreen();

我将混合前两种方法:让Output构造函数通过const-ref获取向量,但将其存储为const指针。这是因为const指针可以被复制,因此如果需要,整个Output对象可以被赋值。

如果可能的话,我会完全避免传递向量,并将unique_ptr的向量封装在Owner中。Output是否可以具有指向Owner的指针/引用,并从Owner获取指向各个Data元素的原始指针?

class Owner {
  private:
    std::vector<std::unique_ptr<Data>> data_vec_;
  public:
    const Data* getData(size_t i) const { return data_vec_.at(i).get(); }
    size_t getSize() const { return data_vec_.size(); }
};
class Output {
  private:
    const Owner& owner_;   
  public:
    Output(const Owner& owner) : owner_(owner) { }
    void doSomething() { 
         // get some data
         auto data = owner_.getData(0);
         // use data...
    }
};