unique_ptr的临时只读副本

时间:2013-04-08 19:46:07

标签: c++ c++11 shared-ptr stdvector unique-ptr

我对C ++ 11的智能指针很陌生,我正试图在项目中有效地使用它们。在我的项目中,我有很多函数对vector的{​​{1}}进行const引用,对它进行一些计算,并将一些结果放在一个返回参数中,如下所示:

unique_ptr

我正在使用void computeCoefficients(const vector<unique_ptr<Scalar>>& roots, vector<unique_ptr<Scalar>>& coeffs) { ... } ,因为调用所有这些函数的过程是unique_ptr中对象的唯一所有者,而函数只是“借用”对象以便将它们读取为输入。

现在我正在尝试编写一个函数来对它收到的vector的不同子集进行计算,为了做到这一点,它需要包含vector的不同“版本”这些子集是为了传递给另一个以vector作为输入的函数。但获取向量子集的唯一方法是复制它 - 这是一个问题,因为vector<unique_ptr<Scalar>> s无法复制。我希望代码看起来像这样:

unique_ptr

当然这不起作用。如果我用void computeOnSet(const vector<unique_ptr<Scalar>>& set, unique_ptr<Scalar>& output) { ... } void computeOnAllSubsets(const vector<unique_ptr<Scalar>>& set, vector<unique_ptr<Scalar>>& outputs) { for(int i = 0; i < input.size(); i++) { auto subset = vector<unique_ptr<Scalar>>(set.begin(), set.begin()+i); subset.insert(subset.end(), set.begin()+i+1, set.end(); computeOnSubset(subset, outputs.at(i)); } } 替换unique_ptr s,我可以使它工作,但这有两个问题:

  • 在哲学上意味着我与shared_ptr函数共享集合的所有权,而我不是;呼叫者仍然是唯一的所有者。 (我读到computeOnSubsets表示你与拥有副本的所有内容共享所有权。)
  • 它会引入引用计数的开销,即使在我不需要它的地方也是如此,因为它会迫使我将所有方法的输入参数更改为shared_ptr

我想做的只是制作指针的临时,只读副本,其唯一目的是制作临时,只读子向量。有没有办法做到这一点? vector<shared_ptr<Scalar>>听起来像我需要的(非拥有临时指针),但它只能与weak_ptr一起使用。

2 个答案:

答案 0 :(得分:10)

  

我正在使用unique_ptr,因为调用所有这些函数的过程是向量中对象的唯一所有者,而函数只是“借用”对象以便将它们作为输入读取。

由于计算函数不拥有指向的对象,只需观察它们的状态并进行计算,你应该向它们传递一个观察指针的向量(在这种情况下,常规原始指针< / strong>),而不是unique_ptr s的向量。

由于computeOnAllSubsets()computeOnSet()不对Scalar个对象的生命周期负责,因此他们甚至不应获得所有权 - 换句话说,他们不应该获得拥有权unique_ptr 1}}秒。

毕竟,程序逻辑保证这些函数不会接收悬空引用,因为拥有函数在执行所有必要的计算之前不会破坏它的向量。您正在编写的内容直接支持:

  

我想要做的只是制作指针的临时只读副本,其唯一目的是制作临时的只读子向量。有没有办法做到这一点?

只需将原始指针向量传递给您的计算函数。给定unique_ptr,您可以通过调用成员函数get()来访问封装的原始指针:

std::unique_ptr<Scalar> pS // ... initialized somehow
Scalar* pScalar = pS.get();

作为原始指针的替代方法,您可以使用std::reference_wrapper来分派观察引用。特别是在重构遗留代码库的过程中,其中原始指针用于手动内存管理,这将清楚地表明所引用对象的所有权属于其他地方。

但请注意,在Modern C ++中,原始指针通常是观察指针的同义词,因此上述区别在广义上下文中并不真正有意义。 std::reference_wrapper是基础的用例是当您想要通过引用传递对象时,通过值接受其参数的某个函数模板(std::bind()是一个典型示例)。

答案 1 :(得分:2)

使用迭代器可能会使您的代码更加通用。只需声明你的计算函数:

template <typename InputIt, typename OutputIt>
void compute(InputIt first_it, InputIt last_it, OutputIt d_first, Output d_last);

此计算函数模板处理范围[first_it, last_it)中的数据,然后将结果放入[d_first, d_last)。它不关心输入或输出容器的类型。迭代器充当容器中元素的指针,这是STL的想法。

此外,在某些情况下,您甚至不会手动浏览范围。只需使用<algorithm>中的功能模板,例如std::for_eachstd::transform

我真的不理解computeOnAllSubsets中的代码段,但我本能地认为std::transform可能会有帮助。