我应该使用std :: shared指针传递指针吗?

Mic*_*ael 21 c++ pointers smart-pointers c++11

假设我有一个由a管理的对象std::unique_ptr.我的代码的其他部分需要访问此对象.传递指针的正确解决方案是什么?我应该只是通过普通指针,std::unique_ptr::get还是应该使用并传递一个std::shared_ptr而不是std::unique_ptr根本?

我有一些偏好,std::unique_ptr因为该指针的所有者实际负责清理.如果我使用共享指针,那么由于共享指针,对象将有可能保持活动状态,即使它实际上应该被销毁.

编辑:不幸的是,我忘了提到指针不仅仅是函数调用的参数,而是存储在其他对象中以构建对象的网络结构.我不喜欢共享指针,因为它不再清楚,谁拥有该对象.

Ric*_*ges 18

如果未传输托管对象的所有权(并且因为它是a unique_ptr,无法共享所有权)那么将被调用函数中的逻辑与所有权概念分开更为正确.我们通过参考调用来做到这一点.

这是一种令人费解的说法:

鉴于:

std::unique_ptr<Thing> thing_ptr;
Run Code Online (Sandbox Code Playgroud)

改变事情:

// declaration
void doSomethingWith(Thing& thing); 

// called like this
doSomethingWith(*thing_ptr);
Run Code Online (Sandbox Code Playgroud)

使用Thing而不修改它.

// declaration
void doSomethingWith(const Thing& thing); 

// called like this
doSomethingWith(*thing_ptr);
Run Code Online (Sandbox Code Playgroud)

您唯一想要unique_ptr在功能签名中提及的是您转移所有权:

// declaration
void takeMyThing(std::unique_ptr<Thing> p);

// call site
takeMyThing(std::move(thing_ptr));
Run Code Online (Sandbox Code Playgroud)

你永远不需要这样做:

void useMyThing(const std::unique_ptr<Thing>& p);
Run Code Online (Sandbox Code Playgroud)

这是一个坏主意的原因是,如果将useMyThing的逻辑与所有权的概念混淆,从而缩小了重用的范围.

考虑:

useMyThing(const Thing& thing);

Thing x;
std::unique_ptr<Thing> thing_ptr = makeAThing();
useMyThing(x);
useMyThing(*thing_ptr);
Run Code Online (Sandbox Code Playgroud)

更新:

注意到问题的更新 - 存储(非拥有)对该对象的引用.

一种方法是确实存储指针.但是,指针遭受逻辑错误的可能性,因为它们可以合法地为空.指针的另一个问题是它们std:: algorithms与容器不兼容- 需要自定义比较功能等.

std::-compliant办法做到这一点 -std::reference_wrapper<>

所以不是这样:

std::vector<Thing*> my_thing_ptrs;
Run Code Online (Sandbox Code Playgroud)

做这个:

std::vector<std::reference_wrapper<Thing>> my_thing_refs;
Run Code Online (Sandbox Code Playgroud)

由于std::reference_wrapper<T>定义了一个运算符T&,您可以reference_wrapped在任何期望的表达式中使用该对象T.

例如:

std::unique_ptr<Thing> t1 = make_thing();
std::unique_ptr<Thing> t2 = make_thing();
std::unique_ptr<Thing> t3 = make_thing();

std::vector<std::reference_wrapper<const Thing>> thing_cache;

store_thing(*t1);
store_thing(*t2);
store_thing(*t3);

int total = 0;
for(const auto& t : thing_cache) {
  total += value_of_thing(t);
}
Run Code Online (Sandbox Code Playgroud)

哪里:

void store_thing(const Thing& t) {
  thing_cache.push_back(std::cref(t));
}

int value_of_thing(const Thing& t) {
  return <some calculation on t>;
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*rew 6

通常,您只需将引用或普通指针传递给希望观察对象的代码的其他部分.

通过引用传递:

void func(const Foo& foo);

std::unique_ptr<Foo> ptr;

// allocate ptr...

if(ptr)
    func(*ptr);
Run Code Online (Sandbox Code Playgroud)

通过原始指针传递:

void func(const Foo* foo);

std::unique_ptr<Foo> ptr;

// allocate ptr...

func(ptr.get());
Run Code Online (Sandbox Code Playgroud)

选择将取决于传递空指针的需要.

您有责任确保观察者unique_ptr在销毁后不使用指针或参考.如果你不能保证那么你必须使用shared_ptr而不是a unique_ptr.观察员可以持有一个weak_ptr表明他们没有所有权的人.

编辑:即使观察者希望坚持指针或参考,但它确实使得确保它在unique_ptr被破坏后不会被使用更加困难.