智能指针的优缺点
我了解到智能指针用于资源管理并且支持RAII。
但是,在哪些特殊情况下,智能指针看起来并不智能,并且在使用时需要注意哪些事项?
I came to know that smart pointer is used for resource management and supports RAII.
But what are the corner cases in which smart pointer doesn't seem smart and things to be kept in mind while using it ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
智能指针无助于防止图形结构中的循环。
例如,对象 A 持有一个指向对象 B 的智能指针,而对象 B 又返回到对象 A。如果在断开 A 与 B(或 B 与 A 的连接)之前释放指向 A 和 B 的所有指针,则 A 和 B 将互相持有对方并形成愉快的内存泄漏。
垃圾收集可以帮助解决这个问题 - 它可以看到两个对象都无法访问并释放它们。
Smart pointers don't help against loops in graph-like structures.
For example, object A holds a smart pointer to object B and object B - back to object A. If you release all pointers to both A and B before disconnection A from B (or B from A) both A and B will hold each other and form a happy memory leak.
Garbage collection could help against that - it could see that both object are unreachable and free them.
我想提一下性能限制。智能指针通常使用原子操作(如 InterlockedIncrement 在 Win32 API 中)用于引用计数。这些函数比普通整数运算要慢得多。
在大多数情况下,这种性能损失不是问题,只需确保不要对智能指针对象创建太多不必要的副本(最好在函数调用中通过引用传递智能指针)。
I would like to mention performance limitations. Smart pointers usually use atomic operations (such as InterlockedIncrement in Win32 API) for reference counting. These functions are significantly slower than plain integer arithmetic.
In most cases, this performance penalty is not a problem, just make sure you don't make too many unnecessary copies of the smart pointer object (prefer to pass the smart pointer by reference in function calls).
这非常有趣:智能指针。
这是 Andrei Alexandrescu 所著的《Modern C++ Design》中的示例章节。
This is quite interesting: Smart Pointers.
It's a sample chapter from "Modern C++ Design" by Andrei Alexandrescu.
注意转换 - 在原始指针和智能指针之间分配时。糟糕的智能指针 - 例如
_com_ptr_t
- 允许隐式转换,从而使情况变得更糟。大多数错误发生在转换期间。注意循环 - 如前所述,您需要弱指针来打破循环。然而,在复杂的图表中,这并不总是那么容易做到。
太多选择 - 大多数库提供不同的实现,具有不同的优点/缺点。不幸的是,大多数时候这些不同的变体是不兼容的,这成为混合库时的一个问题。 (比如说,LibA 使用 LOKI,LibB 使用 boost)。必须提前计划
enable_shared_from_this
很糟糕,必须决定intrusive_ptr
、shared_ptr
和weak_ptr
之间的命名约定。的物体很糟糕。对我来说,shared_ptr(或类似功能之一)的最大优势是它在创建时与其销毁策略耦合。 C++ 和 Win32 都提供了很多摆脱事物的方法,这甚至都不好笑。在构造时耦合(不影响指针的实际类型)意味着我将两种策略放在一处。
Watch out at the transitions - when assigning between raw and smart pointers. Bad smart pointers - like
_com_ptr_t
- make it worse by allowing implicit conversions. Most errors happen at the transition.Watch out for cycles - as mentioned, you need weak pointers to break the cycles. However, in a complex graph that's not always easy to do.
Too much choice - most libraries offer different implementations with different advantages / drawbacks. Unfortunately, most of the time these different variants are not compatible, which becomes a probem when mixing libraries. (say, LibA uses LOKI, LibB uses boost). Having to plan ahead for
enable_shared_from_this
sucks, having to decide naming conventions betweenintrusive_ptr
,shared_ptr
andweak_ptr
for a bunch of objects sucks.For me, the single most e advantage of shared_ptr (or one of similar functionality) is that it is coupled to its destruction policy at creation. Both C++ and Win32 offers so many ways of getting rid of things it's not even funny. Coupling at construction time (without affecting the actual type of the pointer) means I have both policies in one place.
除了技术限制(已经提到:循环依赖)之外,我想说关于智能指针最重要的是要记住它仍然是删除堆分配对象的解决方法。
在大多数情况下,堆栈分配以及引用的使用是管理对象生命周期的最佳选择。
Beside technical limitations (already mentioned : circular dependencies), i'd say that the most important thing about smart pointers is to remember that it's still a workaround to get heap-allocated-objects deleted.
Stack allocation is the best option for most cases - along with the use of references - to manage the lifetime of objects.
下面这篇文章是一篇非常有趣的论文
智能指针:不能与他们共存,不能没有他们'他们
The following article is a very interesting paper
Smart Pointers: Can't Live With 'Em, Can't Live Without 'Em
这里有一些事情
weak_ptr
发挥作用的地方。Here are a few things
weak_ptr
come to the rescue.在某些具有循环的数据结构类型中,引用计数存在问题。从多个线程访问智能指针也可能出现问题,对引用计数的并发访问可能会导致问题。 boost中有一个名为 atomic.hpp 可以缓解这个问题。
There is a problem with reference counting in certain types of data structures that have cycles. There can also be problems with accessing smart pointers from multiple threads, concurrent access to reference counts can cause problems. There's a utility in boost called atomic.hpp that can mitigate this problem.
许多人在将智能指针与原始指针(指向相同对象)混合使用时遇到问题。一个典型的例子是与使用原始指针的 API 交互时。
例如;在
boost::shared_ptr
中有一个.get()
函数返回原始指针。如果小心使用,功能会很好,但很多人似乎都会被它绊倒。恕我直言,这是“抽象泄漏”的一个例子。
Many people run into problems when using smart pointers mixed with raw pointers (to the same objects). A typical example is when interacting with an API that uses raw pointers.
For example; in
boost::shared_ptr
there is a.get()
function that returns the raw pointer. Good functionality if used with care, but many people seem to trip on it.IMHO it's an example of a "leaky abstraction".
Raymond Chen 对智能指针的态度是出了名的矛盾。 析构函数实际运行时存在问题(请注意,析构函数在明确定义的时间以明确定义的顺序运行;只是偶尔您会忘记它是在函数中的最后一行之后。
还要记住,“智能指针”是一个相当大的类别。我将
std::vector
包含在该类别中(std::vector
本质上是一个智能数组)。Raymond Chen is notoriously ambivalent about smart pointers. There are issues about when the destructor actually runs (please note, the destructor runs at a well-defined time in a well-defined order; it's just that once in a while you'll forget that it's after the last line in your function).
Also remember that "smart pointer" is a pretty big category. I include
std::vector
in that category (astd::vector
is essentially a smart array).