我应该使用std :: shared指针传递指针吗? [英] Should I use std::shared pointer to pass a pointer?

查看:79
本文介绍了我应该使用std :: shared指针传递指针吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个由 std :: unique_ptr 管理的对象。我的代码的其他部分需要访问此对象。什么是正确的解决方案传递指针?我应该通过 std :: unique_ptr :: get 或应该使用并传递 std :: shared_ptr c> std :: unique_ptr ,因为该指针的所有者实际上负责清理。如果我使用共享指针,有一个机会,对象将保持活着,由于共享指针,即使它实际上应该被销毁。



编辑:不幸的是,我忘了要指出的是,指针不仅仅是一个函数调用的参数,而且它将被存储在其他对象中以构建对象的网络结构。我不喜欢共享指针,因为它不再清楚,谁实际拥有对象。

解决方案

托管对象没有被转移(因为它是一个 unique_ptr ,所有权不能被共享),那么将被调用函数中的逻辑与所有权的概念分开是更正确的。



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



p>

  std :: unique_ptr< Thing> thing_ptr; 

更改Thing:

  //声明
void doSomethingWith(Thing& thing);

//像这样调用
doSomethingWith(* thing_ptr);

使用Thing而不进行修改。

  //声明
void doSomethingWith(const Thing& thing);

//像这样调用
doSomethingWith(* thing_ptr);

您只需要提及 unique_ptr 在函数签名将是如果你正在转让所有权:

  //声明
void takeMyThing :: unique_ptr< Thing> p);

//调用site
takeMyThing(std :: move(thing_ptr));

您从不需要这样做:

  void useMyThing(const std :: unique_ptr< Thing>& p); 

这将是一个坏主意的原因是,如果混淆useMyThing的逻辑与

请考虑:

  useMyThing(const Thing& thing); 

Thing x;
std :: unique_ptr< Thing> thing_ptr = makeAThing();
useMyThing(x);
useMyThing(* thing_ptr);

更新:



问题 - 存储(非所有)对此对象的引用。



一种方法是存储一个指针。然而,指针遭受逻辑错误的可能性,因为它们可以合法地为空。指针的另一个问题是,它们不能很好地与 std :: algorithms 和容器 - 要求自定义比较函数等。



有一个 std :: - 兼容方法来做到这一点 - std :: reference_wrapper<>



而不是这样:

  std :: vector< ; Thing *> my_thing_ptrs; 

执行此操作:

  std :: vector< std :: reference_wrapper< Thing>> my_thing_refs; 

由于 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);
}

其中:

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

int value_of_thing(const Thing& t){
return< t&
}


Suppose I have an object which is managed by an std::unique_ptr. Other parts of my code need to access this object. What is the right solution to pass the pointer? Should I just pass the plain pointer by std::unique_ptr::get or should I use and pass an std::shared_ptr instead of the std::unique_ptr at all?

I have some preference for the std::unique_ptr because the owner of that pointer is actually responsible for cleanup. If I use a shared pointer, there's a chance that the object will remain alive due to a shared pointer even when it should actually be destroyed.

EDIT: Unfortunately, I forgot to mention that the pointer will not just be a an argument to a function call, but it will be stored in other objects to build up a network structure of objects. I do not prefer the shared pointer because then it's no longer clear, who actually owns the object.

解决方案

If the ownership of the managed object is not being transferred (and because it's a unique_ptr, ownership cannot be shared) then it's more correct to separate the logic in the called function from the concept of ownership. We do this by calling by reference.

This is a convoluted way of saying:

Given:

std::unique_ptr<Thing> thing_ptr;

to change the Thing:

// declaration
void doSomethingWith(Thing& thing); 

// called like this
doSomethingWith(*thing_ptr);

to use the Thing without modifying it.

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

// called like this
doSomethingWith(*thing_ptr);

The only time you'd want to mention the unique_ptr in the function signature would be if you were transferring ownership:

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

// call site
takeMyThing(std::move(thing_ptr));

You never need to do this:

void useMyThing(const std::unique_ptr<Thing>& p);

The reason that this would be a bad idea is that if confuses the logic of useMyThing with the concept of ownership, thus narrowing the scope for re-use.

Consider:

useMyThing(const Thing& thing);

Thing x;
std::unique_ptr<Thing> thing_ptr = makeAThing();
useMyThing(x);
useMyThing(*thing_ptr);

Update:

Noting the update to the question - storing (non-owning) references to this object.

One way to do this is indeed to store a pointer. However, pointers suffer from the possibility of a logic error in that they can legally be null. Another problem with pointers is that they do not play nicely with std:: algorithms and containers - requiring custom compare functions and the like.

There is a std::-compliant way to do this - the std::reference_wrapper<>

So rather than this:

std::vector<Thing*> my_thing_ptrs;

do this:

std::vector<std::reference_wrapper<Thing>> my_thing_refs;

Since std::reference_wrapper<T> defines an operator T&, you can use the reference_wrapped object in any expression that would expect a T.

for example:

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);
}

where:

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>;
}

这篇关于我应该使用std :: shared指针传递指针吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆