【发布时间】:2010-09-15 19:10:43
【问题描述】:
我记得在某处读到使用对智能指针的引用会导致内存损坏。这仅仅是因为在智能指针被销毁后使用了它的引用吗?还是引用计数搞砸了?
感谢澄清
【问题讨论】:
-
这与存储对其他类型对象的引用不好的原因相同,对象可能会被破坏并且您将有一个悬空引用。智能指针应该使它们指向的对象保持活动状态,但我们不是在谈论指向的对象,而是在谈论智能指针对象本身。
标签: c++ smart-pointers
我记得在某处读到使用对智能指针的引用会导致内存损坏。这仅仅是因为在智能指针被销毁后使用了它的引用吗?还是引用计数搞砸了?
感谢澄清
【问题讨论】:
标签: c++ smart-pointers
假设您在这里谈论 shared_ptr...
这仅仅是因为使用了 之后智能指针的引用 被毁了吗?
这是一个很好的答案。您可能也不绝对知道您的引用所指的指针的生命周期。
要解决这个问题,您需要研究 boost::weak_ptr。它不参与引用计数。当您需要使用它时,它会为您提供一个 shared_ptr ,一旦您完成它就会消失。它还会让您知道何时收集了引用的指针。
来自weak_ptr 文档
weak_ptr 类模板存储一个 对一个对象的“弱引用” 已由 shared_ptr 管理。到 访问对象,一个weak_ptr可以是 使用 shared_ptr 构造函数或成员 功能锁。当最后 对象的 shared_ptr 消失并且 对象被删除,尝试 从weak_ptr 获取shared_ptr 引用已删除的实例 对象将失败:构造函数将 抛出类型异常 boost::bad_weak_ptr,和 weak_ptr::lock 将返回一个空 shared_ptr.
请注意,expired() 方法也会告诉你你的 ptr 是否还在。
【讨论】:
当使用智能指针(或任何分配管理对象)时,您指望在构造函数/析构函数中定义的行为来管理 refs/derefs/locks/unlocks。因此,这些类型的对象必须是真正的对象才能正确执行。当使用对此类对象(或指针)的引用时,您正在绕过机制(并要求 wedgie)。
【讨论】:
在很多情况下,引用智能指针是个好主意。 一个明显的例子是智能指针类本身的赋值方法,它接受另一个智能指针的引用作为其参数。
创建一个接受智能指针引用的方法意味着该参数不会增加智能指针的内部引用计数。这可以提高性能 - 但可能不会很多。此外,该方法无法对引用或原始智能指针做很多事情。如果您知道这些东西是什么并避免它们,那么通过引用传递就可以了。当然,智能指针的目的是避免必须知道这些事情。
此外,如果您有一个方法可以修改智能指针参数的值,则需要作为引用传递,就像任何其他类型一样。
【讨论】:
智能指针的“智能”部分由智能指针类的构造函数、析构函数、赋值运算符和其他函数管理。通过使用引用,你绕过了这些操作——当你的引用被初始化时构造函数不会被调用,而当你的引用超出范围时析构函数不会被调用。
本质上,对智能指针的引用是一个哑指针,具有后者所带来的所有风险和陷阱。
【讨论】:
我们有定制的智能指针,我们总是养成传递“const refsomething &”的习惯
它不会增加或减少智能指针,因此 - 更重要的是 - 避免了对 InterLockedIncrement/Decrement 的调用,从而避免了 memory fence 以及随之而来的所有事情:总线锁定、缓存失效,...
【讨论】:
将智能指针的引用传递给函数是非常安全的,而且是个好主意。对象可能会消失,但智能指针不会,它会坐在那里说 null 至少直到函数返回。这是在其范围内为智能指针起别名的最佳方式。如果您在引用的内容上使用带有 const 修饰符的引用,那么您就有了一个智能的观察引用:
const smart_ptr<T>&
有趣且有用的是,const 阻止您使用引用来表示智能指针为空并删除对象,但它不会阻止原始智能指针自身为空,并且您的引用将反映该更改。
从函数返回对智能指针的引用会带来各种麻烦。
【讨论】: