我目前正在使用C ++ 0x shared_ptr。我有一个实用程序函数,需要接受一个指向对象的指针,实用程序函数只执行从对象的读取操作,我可以确定该对象在需要取消引用指针时仍然存在。我想知道将智能指针传递给类似函数的最佳做法是什么?我应该通过引用,按值传递智能指针,还是可以获取原始指针并将其传递给函数?另外,哪种方法可以提供最佳性能?
感谢。
答案 0 :(得分:3)
答案 1 :(得分:3)
如果你只取消引用函数体中的指针而不需要存储指针供以后使用(这意味着承担某种共享所有权),那么使函数采用原始指针(或只是一个引用,如果不需要处理null /没有提供的对象)是最灵活的,因为它允许使用任何类型的所有权语义的代码,例如指向本地或静态变量的指针,数组或其他结构的成员或某种类型的智能指针。这是一个几乎普遍的约定,如果你将一个指针传递给一个函数,调用者将该对象保持活动状态直到该函数退出。实际上,您必须处于多线程环境中才能解决这个问题。
只有当您需要存储指针供以后使用时,该功能才需要与调用者合作完成所有权。在这种情况下,您需要传递shared_ptr
,您可以通过值或const引用来执行,因为shared_ptr
复制起来很便宜并不重要。如果您非常关注性能,可以查看哪个更好。
答案 2 :(得分:3)
如果您还要指定指针的所有权,则只需要将智能指针传递给函数。
我最近在向函数传递std :: unique_ptr时写了一篇关于所有权语义的文章。 看看http://timoch.com/blog/2013/04/std-unique_ptr-semantic/
给出结构A:
struct A { int field; };
传递原始指针
// you make no statement of ownership
// the caller stays the owner of the pointed object
void useA(A* ptr) {
// useA simply uses the pointed object
// it should not delete it (because it does not own it)
ptr->field = 2;
}
按值传递
std::vector<std::unique_ptr<A>> container;
// the caller explicitly gives you ownership of the object
void ownA(std::unique_ptr<A> ptr) {
// you can use the pointed object
std::cout << ptr->field << std::endl;
// the object pointed to by ptr is yours
// you can place it in a container that you own
container.push_back(std::move(ptr));
// now container owns the pointed A instance
// if you do not move it using std::move()
// the pointed object is deleted automatically
}
通过非const引用
// the caller is giving you the opportunity to take ownership of the object
// it is free to not take it though
void maybeOwnA(std::unique_ptr<A> & ptr) {
// ptr is passed by reference
// so maybeOwnA can decide based on its own internal
// to take ownership of the pointed object
// taking ownership requires that std::move is called on ptr
// it may also simply use the pointed object and not
// take ownership
}
void callMaybeOwnA() {
std::unique_ptr<A> ptr = new A();
maybeOwnA(ptr);
// we know if we still own the instance of A
// by looking at ptr
if (ptr.get() != nullptr) {
// we still own the pointed object
}
}
传递const-reference
// this is functionally the same as passing a raw pointer
// but you force the caller to use a std::unique_ptr to call you
// the caller will not be able to use a std::shared_ptr for example
// I strongly recommend against this form. Passing a raw pointer is
// perfectly fine
void useA(const std::unique_ptr<A> & ptr) {
// ptr is const so you cannot call std::move on it
// you effectively cannot own it
}
// a factory function should return a std::unique_ptr by value
// the caller owns the pointed object
std::unique_ptr<A> factory() {
return std::unique_ptr<A>(new A());
}
void callFactory() {
std::unique_ptr<A> ptr = factory();
// the pointed object is deleted when ptr goes out of scope
}
同样适用于std :: shared_ptr。如果函数只是使用指针并返回,则没有理由传递std :: shared_ptr。当你的意思是将指向对象的共享所有权提供给你调用的组件时,你只需要传递一个std :: shared_ptr。例如,如果函数将存储指针并期望在它返回后能够使用它(例如,再次调用时)。
希望它有所帮助。
TiMoch
答案 3 :(得分:1)
我会选择第三种选择。如果您正在设计一个使用对象一段时间的函数,并保证对象在整个调用期间都处于活动状态,那么函数签名根本不应该使用指针:
void foo( type & t );
int main() {
std::shared_ptr<type> sp( new type );
foo( *sp );
}
没有理由限制foo
使用shared_ptr
,如上所述,您可以将引用传递给甚至不动态分配的对象。通过不传递指针(甚至不是原始指针),它清楚地表明没有与该函数关联的所有权语义(即它不会保留指针供以后使用,它不会删除该对象),并且它表示该对象应在整个通话期间保持活动状态。
答案 4 :(得分:0)
答案取决于智能指针类型。您可以通过值传递的共享指针,如下所示:
class A
{
// implementation
};
void foo( std::shared_ptr< A > p )
{
// use p
}
但是例如std :: auto_ptr,你无法做到这一点,因为对象被破坏了:
void boo ( std::auto_ptr< A > p )
{
// use p
} // ops the resource pointer by p gets destructed
在第二种情况下,您应该通过引用传递:
void boo ( A &p )
{
// use p
}
答案 5 :(得分:0)
答案非常简单 - 用相对便宜的复制费用做任何其他课程。
注意复制智能指针并不像复制整数那样便宜。它可能介于整数和小std :: string之间。 (我在一个项目中工作,所有智能指针都按值发送,并且递增和递减智能指针的引用计数占用了4-6%的时间)。
如果您希望通过引用传递std :: string,例如,您也应该为智能指针执行此操作。
如果你使用引用(我个人推荐)使用const引用 - 这样你就可以让编译器在需要它的地方进行引用类的隐式upcast。