C++ 标准::参考包装<;T>;容器中的用法

C++ 标准::参考包装<;T>;容器中的用法,c++,c++11,containers,C++,C++11,Containers,如果可以,我会从代码中删除所有原始指针*,因为使用它们可能不是线程安全的,而且设计意图也不明确(可选值、所有权等)。 然而,有时不使用指针并不容易。例如,我们倾向于在多态类型的容器中为基类型使用指针: class A : noncopyable { ... }; class B : public A { ... }; std::vector<A*> v; v.emplace_back(new B); // temporary container for some operatio

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

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
拥有这些对象,但我仍然不喜欢
selected
有一个原始指针,使我的设计不直观。查看标准C++库,我认为只有一种类型可以完成这项工作:
std::vector v;
v、 将_放回(使_唯一());
//用于某些操作的临时容器
std::选择载体;
if(check())
已选定。向后放置(*v.front());
你觉得这个代码怎么样?这是一种好的做法吗?我知道
std::ref()
std::cref
主要用于模板,但这里我们似乎也可以使用它来清楚地说明我们的设计意图。我看到的唯一问题是,我必须用
get()
解除对
std::reference_wrapper
的引用,并且内部没有
操作符*()
操作符->()
来拥有与容器中的
unique\ptr>相同的界面。我应该自己写类似的东西吗?或者,在将来的C++版本中,可以为RealthyS包装器扩展这种用例?请分享您的反馈


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

我认为将它们称为
共享\u ptr
在逻辑上没有错误。然而,从以下定义来看:

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


它可能是一个更好的候选人。至少当你在
选中的
中摆弄指针时,你需要暂时拥有它。由于原始指针存储在共享指针中,因此使用弱指针会更安全。

您已经提供了一个看起来不错的解决方案。我知道问题是“你感觉如何?”

我个人的感觉是,在安全性和明确性与代码的简单性之间需要存在某种平衡。看起来,您的解决方案可能太难实现安全性,并且过分牺牲了简单性。每当我使用包含“弱引用”的容器时,我都使用原始指针来表示这些引用。诚然,这可能会使对象的所有者不那么清楚,但它也有一些优点:您不必研究什么是“reference_wrapper”,代码也很清楚。如果您只是暂时使用它们(弱引用的容器),并且封装了这种用法,那么所有权问题应该是最小的

但我想这只是个人偏好的问题。我建议使用不同的类型来达到相同的目的。前提是您能够负担使用Boost的费用。对于“强”引用(拥有资源),您可以使用Steve Watanabe的库。它不需要显式使用空闲存储内存,我认为对于小型类型,它可以完全不用使用堆内存(使用小型缓冲区优化)。它最近已被接受,以提高,虽然还没有发布,我想

对于弱引用,考虑使用Booost可选引用(可选):

int i = 0;
boost::optional<int&> oi = i; // note: int&
i = 2;
assert(*oi == 2);
inti=0;
boost::可选oi=i;//注:int&
i=2;
断言(*oi==2);

它与reference_包装器具有相同的语义

所选
的生存期是多少?是否保证在其元素指向的对象被销毁之前销毁(或清空)?如果是这样,那么使用原始指针:不需要共享所有权。在C++中使用原始指针没有什么错;只需确保原始指针不拥有指向对象。这听起来像是
共享的\u ptr
。@JamesMcNellis你是对的。我想从这样一个小片段中可以清楚地看出
selected
v
是什么意思。然而,在更大的范围/类别中,要看到设计中的关系并不那么容易。在某些方法中,您开始只处理所选的
,而不查看
v
,您开始想知道这里的指针是什么意思。它是可选值、所有权还是仅仅是基类指针?我正在寻找一种很好的方式来表达我的设计意图,而不需要运行时的开销。@perreal std::shared\u ptr在其他情况下可能是一个很好的解决方案,但是在这里,我希望
v
拥有严格的所有权,其他潜在的容器是临时容器,用于对成员执行一些操作(即排序、子集等)。嗯,这会奏效的。但是,我不喜欢
std::shared\u ptr
的运行时和内存开销。我只在我真正需要它们的时候才使用它们->共享所有权。有人可能会说,在某个时候,你正在共享所有权。否则,请继续在“选定”中使用裸指针。@MateuszPusz在用于唯一所有权时,不要忘记共享所有权的“概念开销”。@ChristianRau,您是否需要在删除指针之前三思而后行,因为可能有人试图使用它?自C++17以来,我们有
std::optional
,但它不允许引用,因为人们无法就复制/分配可选引用时应具有的语义达成一致。因此,
std::
中最接近的东西是
std::optional
。这种情况下的语义,大概与
boost::
版本一样,是复制构造并重新绑定包装中的引用,而不是在引用对象之间赋值。(我不知道为什么这样比较好,但必须这样做
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());
int i = 0;
boost::optional<int&> oi = i; // note: int&
i = 2;
assert(*oi == 2);