std :: reference_wrapper <t>容器中的用法</t>

时间:2012-12-14 07:53:22

标签: c++ c++11 containers

如果可以的话,我会从代码中删除所有原始指针*,因为使用它们可能不是线程安全的,并且设计的意图不明确(可选值,所有权等)。 但有时候不使用指针并不容易。例如,我们倾向于在多态类型的容器中使用指针作为基类型:

class A : noncopyable { ... };
class B : public A { ... };

std::vector<A*> v;
v.emplace_back(new B);

// temporary container for some operation
std::vector<A*> selected;
if(check())
   selected.emplace_back(v.front());

您对上述代码有什么看法?谁是老板?它是共享所有权吗?这就是为什么我们应该为v

做到这一点
std::vector<std::unique_ptr<A>> v;
v.emplace_back(make_unique<B>());

现在很明显v拥有对象,但我仍然不喜欢selected有一个原始指针并使我的设计不直观。查看标准C ++库我认为只有一种类型可以完成这项工作 - std::reference_wrapper

std::vector<std::unique_ptr<A>> v;
v.emplace_back(make_unique<B>());

// temporary container for some operation
std::vector<std::reference_wrapper<A>> selected;
if(check())
  selected.emplace_back(*v.front());

您对该代码有何看法?这是一个好习惯吗?我知道std::ref()std::cref意味着主要使用模板,但似乎在这里我们也可以用它来清楚地说明我们的设计意图。我看到的唯一问题是我必须使用std::reference_wrapper取消引用get()并且内部没有operator*()operator->()来拥有相同的界面,就像在{{ 1}}。我应该自己写类似的东西吗?或者也许在未来的C ++版本中可以为这样的用例扩展reference_wrapper?请分享您的反馈意见。

编辑:我更改了代码示例,以便更好地显示意图。

2 个答案:

答案 0 :(得分:5)

您已经提供了一个看起来很健全的解决方案。我明白问题是“你觉得怎么样?”

我个人的感觉是,一方面需要在安全性和明确性之间存在一些平衡,另一方面需要在代码的简单性方面保持平衡。看起来您的解决方案可能会过于强烈地将其推向安全并且过于简单地损害其简单性。每当我使用容纳“弱引用”的容器时,我使用原始指针来表示这些。没错,这可能会让对象的所有者不太清楚,但它也有一些优点:你不必研究“reference_wrapper”是什么,代码是清楚的。如果您仅暂时使用它们(弱引用的容器)并且您封装了此用法,则所有权问题应该是最小的。

但我猜这只是个人偏好的问题。我只是建议为同一目的使用不同的类型。这是你可以负担得起使用Boost。对于“强大”引用(拥有资源),您可以使用Steve Watanabe的Type Erasure库。它不需要显式使用免费存储内存,我想对于小型类型,它可以完全避免使用堆内存(使用小缓冲区优化)。最近Boost已经接受了它,虽然尚未发布,但我认为。

对于弱引用,请考虑在Boost.Optional中使用“可选引用”:

int i = 0;
boost::optional<int&> oi = i; // note: int&
i = 2;
assert(*oi == 2);

它与reference_wrapper具有相同的语义。

答案 1 :(得分:0)

我认为称他们为shared_ptr并不是逻辑错误。但是,看一下std::weak_ptr的定义:

  

std :: weak_ptr是一个智能指针,它拥有一个非拥有者(“弱”)   引用由std :: shared_ptr管理的对象。肯定是   转换为std :: shared_ptr以访问引用的对象。

它可能是一个更好的候选人。至少当你通过selected摆弄指针时,你需要承担临时所有权。由于原始指针存储在共享指针中,因此使用弱指针将更安全。