返回智能指针的最佳实践。

时间:2021-02-22 21:18:00

What is the best practice when returning a smart pointer, for example a boost::shared_ptr? Should I by standard return the smart pointer, or the underlying raw pointer? I come from C# so I tend to always return smart pointers, because it feels right. Like this (skipping const-correctness for shorter code):

在返回智能指针时,最佳实践是什么,例如boost: shared_ptr?我应该按标准返回智能指针,还是原始指针?我来自c#,所以我总是返回智能指针,因为感觉是对的。如下(跳过简短代码的const-correct):

class X
{
public:
    boost::shared_ptr<Y> getInternal() {return m_internal;}

private:
    boost::shared_ptr<Y> m_internal;
}

However I've seen some experienced coders returning the raw pointer, and putting the raw pointers in vectors. What is the right way to do it?

不过,我见过一些经验丰富的程序员返回原始指针,并将原始指针放在vector中。正确的做法是什么?

9 个解决方案

#1


22  

There is no "right" way. It really depends on the context.

没有“正确”的方法。这取决于环境。

You can internally handle memory with a smart pointer and externally give references or raw pointers. After all, the user of your interface doesn't need to know how you manage memory internally. In a synchronous context this is safe and efficient. In an asynchronous context, there are many pitfalls.

您可以使用智能指针在内部处理内存,并在外部提供引用或原始指针。毕竟,用户不需要知道如何在内部管理内存。在同步上下文中,这是安全和有效的。在异步上下文中,有许多缺陷。

If you're unsure about what to do you can safely return smart pointers to your caller. The object will be deallocated when the references count reaches zero. Just make sure that you don't have a class that keeps smart pointers of objects for ever thus preventing the deallocation when needed.

如果你不确定该怎么做,你可以安全地将智能指针返回给你的调用者。当引用计数为0时,对象将被释放。只要确保您没有保存对象的智能指针的类,从而在需要时防止重新分配。

As a last note, in C++ don't overuse dynamically allocated objects. There are many cases where you don't need a pointer and can work on references and const references. That's safer and reduces the pressure on the memory allocator.

最后,在c++中,不要过度使用动态分配的对象。在许多情况下,您不需要指针,可以处理引用和const引用。这样更安全,也减少了内存分配器的压力。

#2


11  

It depends on what the meaning of the pointer is.

这取决于指针的含义。

When returning a shared_pointer, you are syntactically saying "You will share ownership of this object", such that, if the the original container object dies before you release your pointer, that object will still exist.

当返回shared_pointer时,语法上说“您将共享该对象的所有权”,这样,如果在释放指针之前原始容器对象死亡,该对象仍然存在。

Returning a raw pointer says: "You know about this object, but don't own it". It's a way of passing control, but not keeping the lifetime tied to the original owner.

返回一个原始指针:“您知道这个对象,但不拥有它”。这是一种传递控制的方式,但不会让你的生命与原来的所有者联系在一起。

(in some older c-programs, it means "It's now your problem to delete me", but I'd heavily recommend avoiding this one)

(在一些较老的c程序中,它的意思是“删除我现在是你的问题”,但我强烈建议避免这个)

Typically, defaulting to shared saves me a lot of hassle, but it depends on your design.

通常情况下,默认共享会省去我很多麻烦,但这取决于您的设计。

#3


8  

I follow the following guidelines for passing pointers arguments to functions and returning pointers:

我遵循以下准则,将指针参数传递给函数和返回指针:

boost::shared_ptr

API and client are sharing ownership of this object. However you have to be careful to avoid circular references with shared_ptr, if the objects represent some kind of graph. I try to limit my use of shared_ptr for this reason.

API和客户端共享这个对象的所有权。但是,如果对象表示某种图形,则必须小心避免使用shared_ptr的循环引用。出于这个原因,我试图限制shared_ptr的使用。

boost::weak_ptr / raw pointer

API owns this object, you are allowed share it while it is valid. If there is a chance the client will live longer than the api I use a weak_ptr.

API拥有这个对象,允许您在它有效时共享它。如果有机会,客户端将比我使用weak_ptr的api更长寿。

std::auto_ptr

API is creating an object but the client owns the object. This ensures that the returning code is exception safe, and clearly states that ownership is being transferred.

API正在创建一个对象,但客户端拥有该对象。这确保返回的代码是异常安全的,并且清楚地说明了所有权正在被转移。

boost::scoped_ptr

For pointers to objects stored on the stack or as class member variables. I try to use scoped_ptr first.

用于指向存储在堆栈上的对象或作为类成员变量的指针。我尝试先使用scoped_ptr。

Like all guidelines there will be times when the rules conflict or have to be bent, then I try to use intelligence.

就像所有的指导方针一样,有时规则会发生冲突,或者不得不做出让步,然后我就会尝试运用智慧。

#4


7  

I typically return "owning"/"unique" smart pointers from factories or similar to make it clear who is responsible for cleaning up.

我通常会从工厂返回“拥有”/“唯一的”智能指针,或者类似地说明谁负责清理。

This example https://ideone.com/qJnzva shows how to return a std::unique_ptr that will be deleted when the scope of the variable that the caller assigns the value to goes out of scope.

这个示例https://ideone.com/qJnzva展示了如何返回一个std::unique_ptr,当调用者分配值的变量的作用域超出作用域时,它将被删除。

While it's true that the smart pointer deletes its own pointer, the lifetime of the variable holding the smart pointer is 100% controlled by the caller, so the caller decides when the pointer is deleted. However, since it's a "unique" and "owning" smart pointer, no other client can control the lifetime.

虽然智能指针确实删除了它自己的指针,但是保存智能指针的变量的生命周期100%由调用方控制,因此调用方决定何时删除指针。但是,由于它是“唯一的”和“拥有的”智能指针,没有任何其他客户机可以控制生命周期。

#5


4  

I would never return a raw pointer, instead I would return a weak_ptr to tell the user of the pointer that he doesn't have the control over the resource.

我永远不会返回原始指针,而是返回weak_ptr,告诉指针的用户他没有对资源的控制。

If you return a weak_ptr its very unlikely that there will be dangling pointers in the application.

如果返回weak_ptr,那么应用程序中不太可能出现悬空指针。

If there is a performance problem I would return a reference to the object and a hasValidXObject method.

如果有性能问题,我将返回对象的引用和hasValidXObject方法。

#6


3  

In my opinion, in C++, you should always have to justify the use of an unguarded pointer.

在我看来,在c++中,您应该始终证明使用无保护指针是合理的。

There could be many valid reasons: a need for very high performance, for very low memory usage, for dealing with legacy libraries, because of some issue with the underlying data structure the pointer is storing. But [dynamically allocated] pointers are somewhat 'evil', in that you have to deallocate the memory at every possible execution path and you will almost certainly forget one.

有很多合理的原因:需要非常高的性能、非常低的内存使用、处理遗留库,因为指针存储的底层数据结构存在一些问题。但是(动态分配的)指针有点“邪恶”,因为您必须在每个可能的执行路径上分配内存,几乎肯定会忘记一个。

#7


0  

I wouldn't put raw pointers in vectors.

我不会在向量中加入原始指针。

In case they use auto_ptr or boost::scoped_ptr, they can't use (or return) anything but raw pointers. That could explain their way of coding, i guess.

如果他们使用auto_ptr或boost: scoped_ptr,他们只能使用(或返回)原始指针。我想这可以解释他们的编码方式。

#8


0  

depends on your goals.

取决于你的目标。

blindly returning smart ptr to internal data might not be a good idea (which is very sensitive to the task you're trying to solve) - you might be better off just offering some doX() and doY() that use the pointer internally instead.

盲目地将智能ptr返回到内部数据可能不是一个好主意(这对您试图解决的任务非常敏感)——您最好只提供一些内部使用指针的doX()和doY()。

on the other hand, if returning the smart ptr, you should also consider that you'll create no mutual circular references when objects end up unable to destroy each other (weak_ptr might be a better option in that case).

另一方面,如果返回smart ptr,您还应该考虑,当对象最终无法相互破坏时,您将不会创建相互循环引用(在这种情况下,weak_ptr可能是更好的选择)。

otherwise, like already mentioned above, performance/legacy code/lifetime considerations should all be taken into account.

否则,就像上面已经提到的,性能/遗留代码/生命周期考虑都应该考虑在内。

#9


-1  

const boost::shared_ptr &getInternal() {return m_internal;}

const boost:::shared_ptr &getInternal() {return m_internal;}

This avoids a copy.

这可以避免一个副本。

Sometimes you'll like to return a reference, for example:

有时你想要返回一个引用,例如:

  • Y &operator*() { return *m_internal; }
  • y&operator *(){返回*m_internal;}
  • const Y &operator*() const { return *m_internal; }
  • const Y &operator*() const {return *m_internal;}

This is good too only if the reference will be used and discarded inmediately. The same goes for a raw pointer. Returning a weak_ptr is also an option.

这也很好,只有当参考资料将被使用和立即丢弃。原始指针也是如此。返回一个weak_ptr也是一个选项。

The 4 are good depending on the goals. This question requires a more extensive discussion.

这4个目标都是好的。这个问题需要更广泛的讨论。

#1


22  

There is no "right" way. It really depends on the context.

没有“正确”的方法。这取决于环境。

You can internally handle memory with a smart pointer and externally give references or raw pointers. After all, the user of your interface doesn't need to know how you manage memory internally. In a synchronous context this is safe and efficient. In an asynchronous context, there are many pitfalls.

您可以使用智能指针在内部处理内存,并在外部提供引用或原始指针。毕竟,用户不需要知道如何在内部管理内存。在同步上下文中,这是安全和有效的。在异步上下文中,有许多缺陷。

If you're unsure about what to do you can safely return smart pointers to your caller. The object will be deallocated when the references count reaches zero. Just make sure that you don't have a class that keeps smart pointers of objects for ever thus preventing the deallocation when needed.

如果你不确定该怎么做,你可以安全地将智能指针返回给你的调用者。当引用计数为0时,对象将被释放。只要确保您没有保存对象的智能指针的类,从而在需要时防止重新分配。

As a last note, in C++ don't overuse dynamically allocated objects. There are many cases where you don't need a pointer and can work on references and const references. That's safer and reduces the pressure on the memory allocator.

最后,在c++中,不要过度使用动态分配的对象。在许多情况下,您不需要指针,可以处理引用和const引用。这样更安全,也减少了内存分配器的压力。

#2


11  

It depends on what the meaning of the pointer is.

这取决于指针的含义。

When returning a shared_pointer, you are syntactically saying "You will share ownership of this object", such that, if the the original container object dies before you release your pointer, that object will still exist.

当返回shared_pointer时,语法上说“您将共享该对象的所有权”,这样,如果在释放指针之前原始容器对象死亡,该对象仍然存在。

Returning a raw pointer says: "You know about this object, but don't own it". It's a way of passing control, but not keeping the lifetime tied to the original owner.

返回一个原始指针:“您知道这个对象,但不拥有它”。这是一种传递控制的方式,但不会让你的生命与原来的所有者联系在一起。

(in some older c-programs, it means "It's now your problem to delete me", but I'd heavily recommend avoiding this one)

(在一些较老的c程序中,它的意思是“删除我现在是你的问题”,但我强烈建议避免这个)

Typically, defaulting to shared saves me a lot of hassle, but it depends on your design.

通常情况下,默认共享会省去我很多麻烦,但这取决于您的设计。

#3


8  

I follow the following guidelines for passing pointers arguments to functions and returning pointers:

我遵循以下准则,将指针参数传递给函数和返回指针:

boost::shared_ptr

API and client are sharing ownership of this object. However you have to be careful to avoid circular references with shared_ptr, if the objects represent some kind of graph. I try to limit my use of shared_ptr for this reason.

API和客户端共享这个对象的所有权。但是,如果对象表示某种图形,则必须小心避免使用shared_ptr的循环引用。出于这个原因,我试图限制shared_ptr的使用。

boost::weak_ptr / raw pointer

API owns this object, you are allowed share it while it is valid. If there is a chance the client will live longer than the api I use a weak_ptr.

API拥有这个对象,允许您在它有效时共享它。如果有机会,客户端将比我使用weak_ptr的api更长寿。

std::auto_ptr

API is creating an object but the client owns the object. This ensures that the returning code is exception safe, and clearly states that ownership is being transferred.

API正在创建一个对象,但客户端拥有该对象。这确保返回的代码是异常安全的,并且清楚地说明了所有权正在被转移。

boost::scoped_ptr

For pointers to objects stored on the stack or as class member variables. I try to use scoped_ptr first.

用于指向存储在堆栈上的对象或作为类成员变量的指针。我尝试先使用scoped_ptr。

Like all guidelines there will be times when the rules conflict or have to be bent, then I try to use intelligence.

就像所有的指导方针一样,有时规则会发生冲突,或者不得不做出让步,然后我就会尝试运用智慧。

#4


7  

I typically return "owning"/"unique" smart pointers from factories or similar to make it clear who is responsible for cleaning up.

我通常会从工厂返回“拥有”/“唯一的”智能指针,或者类似地说明谁负责清理。

This example https://ideone.com/qJnzva shows how to return a std::unique_ptr that will be deleted when the scope of the variable that the caller assigns the value to goes out of scope.

这个示例https://ideone.com/qJnzva展示了如何返回一个std::unique_ptr,当调用者分配值的变量的作用域超出作用域时,它将被删除。

While it's true that the smart pointer deletes its own pointer, the lifetime of the variable holding the smart pointer is 100% controlled by the caller, so the caller decides when the pointer is deleted. However, since it's a "unique" and "owning" smart pointer, no other client can control the lifetime.

虽然智能指针确实删除了它自己的指针,但是保存智能指针的变量的生命周期100%由调用方控制,因此调用方决定何时删除指针。但是,由于它是“唯一的”和“拥有的”智能指针,没有任何其他客户机可以控制生命周期。

#5


4  

I would never return a raw pointer, instead I would return a weak_ptr to tell the user of the pointer that he doesn't have the control over the resource.

我永远不会返回原始指针,而是返回weak_ptr,告诉指针的用户他没有对资源的控制。

If you return a weak_ptr its very unlikely that there will be dangling pointers in the application.

如果返回weak_ptr,那么应用程序中不太可能出现悬空指针。

If there is a performance problem I would return a reference to the object and a hasValidXObject method.

如果有性能问题,我将返回对象的引用和hasValidXObject方法。

#6


3  

In my opinion, in C++, you should always have to justify the use of an unguarded pointer.

在我看来,在c++中,您应该始终证明使用无保护指针是合理的。

There could be many valid reasons: a need for very high performance, for very low memory usage, for dealing with legacy libraries, because of some issue with the underlying data structure the pointer is storing. But [dynamically allocated] pointers are somewhat 'evil', in that you have to deallocate the memory at every possible execution path and you will almost certainly forget one.

有很多合理的原因:需要非常高的性能、非常低的内存使用、处理遗留库,因为指针存储的底层数据结构存在一些问题。但是(动态分配的)指针有点“邪恶”,因为您必须在每个可能的执行路径上分配内存,几乎肯定会忘记一个。

#7


0  

I wouldn't put raw pointers in vectors.

我不会在向量中加入原始指针。

In case they use auto_ptr or boost::scoped_ptr, they can't use (or return) anything but raw pointers. That could explain their way of coding, i guess.

如果他们使用auto_ptr或boost: scoped_ptr,他们只能使用(或返回)原始指针。我想这可以解释他们的编码方式。

#8


0  

depends on your goals.

取决于你的目标。

blindly returning smart ptr to internal data might not be a good idea (which is very sensitive to the task you're trying to solve) - you might be better off just offering some doX() and doY() that use the pointer internally instead.

盲目地将智能ptr返回到内部数据可能不是一个好主意(这对您试图解决的任务非常敏感)——您最好只提供一些内部使用指针的doX()和doY()。

on the other hand, if returning the smart ptr, you should also consider that you'll create no mutual circular references when objects end up unable to destroy each other (weak_ptr might be a better option in that case).

另一方面,如果返回smart ptr,您还应该考虑,当对象最终无法相互破坏时,您将不会创建相互循环引用(在这种情况下,weak_ptr可能是更好的选择)。

otherwise, like already mentioned above, performance/legacy code/lifetime considerations should all be taken into account.

否则,就像上面已经提到的,性能/遗留代码/生命周期考虑都应该考虑在内。

#9


-1  

const boost::shared_ptr &getInternal() {return m_internal;}

const boost:::shared_ptr &getInternal() {return m_internal;}

This avoids a copy.

这可以避免一个副本。

Sometimes you'll like to return a reference, for example:

有时你想要返回一个引用,例如:

  • Y &operator*() { return *m_internal; }
  • y&operator *(){返回*m_internal;}
  • const Y &operator*() const { return *m_internal; }
  • const Y &operator*() const {return *m_internal;}

This is good too only if the reference will be used and discarded inmediately. The same goes for a raw pointer. Returning a weak_ptr is also an option.

这也很好,只有当参考资料将被使用和立即丢弃。原始指针也是如此。返回一个weak_ptr也是一个选项。

The 4 are good depending on the goals. This question requires a more extensive discussion.

这4个目标都是好的。这个问题需要更广泛的讨论。