返回智能指针时的最佳实践
返回智能指针(例如 boost::shared_ptr)时的最佳实践是什么? 我应该按照标准返回智能指针还是底层原始指针? 我来自 C#,所以我倾向于总是返回智能指针,因为感觉不错。 像这样(跳过较短代码的常量正确性):
class X
{
public:
boost::shared_ptr<Y> getInternal() {return m_internal;}
private:
boost::shared_ptr<Y> m_internal;
}
但是,我看到一些经验丰富的编码人员返回原始指针,并将原始指针放入向量中。 正确的做法是什么?
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):
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
没有“正确”的方法。 这确实取决于上下文。
您可以使用智能指针在内部处理内存,并在外部提供引用或原始指针。 毕竟,界面的用户不需要知道您如何在内部管理内存。 在同步上下文中,这是安全且高效的。 在异步上下文中,存在许多陷阱。
如果您不确定该怎么做,您可以安全地将智能指针返回给调用者。 当引用计数达到零时,该对象将被释放。 只需确保您没有一个类可以永远保留对象的智能指针,从而防止在需要时进行释放。
最后一点,在 C++ 中不要过度使用动态分配的对象。 在很多情况下,您不需要指针并且可以处理引用和常量引用。 这样更安全,并减少了内存分配器的压力。
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.
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.
这取决于指针的含义。
当返回一个shared_pointer时,你在语法上是说“你将共享这个对象的所有权”,这样,如果原始容器对象在你释放指针之前死亡,那么该对象仍然存在。
返回一个原始指针表示:“你知道这个对象,但不拥有它”。 这是一种传递控制权的方式,但不会将生命周期与原始所有者联系在一起。
(在一些较旧的 C 程序中,这意味着“现在删除我是你的问题”,但我强烈建议避免这种情况)
通常,默认为共享可以节省很多麻烦,但这取决于你的设计。
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.
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)
Typically, defaulting to shared saves me a lot of hassle, but it depends on your design.
我遵循以下准则将指针参数传递给函数并返回指针:
API 和客户端共享该对象的所有权。 但是,如果对象表示某种图形,则必须小心避免使用
shared_ptr
进行循环引用。 由于这个原因,我尝试限制对shared_ptr
的使用。API拥有该对象,您可以在其有效期间共享它。 如果客户端有可能比 api 的寿命更长,我会使用weak_ptr。
API 正在创建一个对象,但客户端拥有该对象。 这确保返回的代码是异常安全的,并清楚地表明所有权正在转移。
用于指向存储在堆栈上或作为类成员变量的对象的指针。 我首先尝试使用
scoped_ptr
。就像所有的指导方针一样,有时规则会发生冲突或必须改变,然后我会尝试使用智慧。
I follow the following guidelines for passing pointers arguments to functions and returning pointers:
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 ofshared_ptr
for this reason.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 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.
For pointers to objects stored on the stack or as class member variables. I try to use
scoped_ptr
first.Like all guidelines there will be times when the rules conflict or have to be bent, then I try to use intelligence.
我通常会从工厂或类似的地方返回“拥有”/“唯一”智能指针,以明确谁负责清理。
此示例 https://ideone.com/qJnzva 展示了如何返回
std::unique_ptr< /code> 当调用者赋值的变量范围超出范围时将被删除。
虽然智能指针确实删除了自己的指针,但保存智能指针的变量的生命周期是 100% 由调用者控制的,因此调用者决定何时删除指针。 然而,由于它是一个“唯一”且“拥有”的智能指针,没有其他客户端可以控制其生命周期。
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.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.
我永远不会返回原始指针,而是返回一个weak_ptr来告诉指针的用户他无法控制资源。
如果返回一个weak_ptr,应用程序中不太可能存在悬空指针。
如果存在性能问题,我将返回对该对象的引用和 hasValidXObject 方法。
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.
If you return a weak_ptr its very unlikely that there will be dangling pointers in the application.
If there is a performance problem I would return a reference to the object and a hasValidXObject method.
我认为,在 C++ 中,您应该始终必须证明使用不受保护的指针的合理性。
可能有很多正当的理由:由于指针存储的底层数据结构存在一些问题,需要非常高的性能、非常低的内存使用量、处理遗留库。 但是[动态分配]指针有点“邪恶”,因为您必须在每个可能的执行路径上释放内存,并且您几乎肯定会忘记一个。
In my opinion, in C++, you should always have to justify the use of an unguarded pointer.
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.
我不会将原始指针放入向量中。
如果他们使用 auto_ptr 或 boost::scoped_ptr,他们不能使用(或返回)除了原始指针之外的任何东西。 我想这可以解释他们的编码方式。
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.
取决于你的目标。
盲目地将智能 ptr 返回到内部数据可能不是一个好主意(这对您要解决的任务非常敏感) - 您最好只提供一些在内部使用指针的 doX() 和 doY() 。
另一方面,如果返回智能 ptr,您还应该考虑到当对象最终无法相互销毁时,您将不会创建相互循环引用(在这种情况下,weak_ptr 可能是更好的选择)。
否则,就像上面已经提到的那样,性能/遗留代码/生命周期的考虑都应该被考虑在内。
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.
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).
otherwise, like already mentioned above, performance/legacy code/lifetime considerations should all be taken into account.
const boost::shared_ptr &getInternal() {return m_internal;}
这避免了复制。
有时您会想返回一个引用,例如:
仅当引用将被使用并立即丢弃时,这也很好
原始指针也是如此。
返回weak_ptr也是一种选择。
这 4 个都很好,具体取决于目标。 这个问题需要更广泛的讨论。
const boost::shared_ptr &getInternal() {return m_internal;}
This avoids a copy.
Sometimes you'll like to return a reference, for example:
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.
The 4 are good depending on the goals. This question requires a more extensive discussion.