我应该使用std :: shared指针传递指针吗? [英] Should I use std::shared pointer to pass a pointer?
问题描述
假设我有一个由 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屋!