【问题标题】:What are all the ways use_count of std::shared_ptr is incremented?std::shared_ptr 的 use_count 增加的所有方式是什么?
【发布时间】:2014-11-05 21:59:41
【问题描述】:

我有两个shared_ptrs 指向同一个int,即在它们上调用get() 返回相同的地址。但是对它们调用use_count() 会返回1。当它们中的最后一个超出范围时,它会尝试释放另一个已经释放的内存,从而导致双重释放运行时错误:

#include <memory>
#include <iostream>
using namespace std;

int main() {
    shared_ptr<int> sp1(make_shared<int>(7));
    shared_ptr<int> sp2(&(*sp1));
    cout << sp1.use_count() << endl;  // 1
    cout << sp2.use_count() << endl;  // 1
    cout << sp1.get() << endl;        // same address
    cout << sp2.get() << endl;        // same address
}
// ^ Double free runtime error at closing brace.

同样的事情发生在这个带有显式声明的原始指针的变体中:

int main() {
    int *raw_ptr = new int(8);
    shared_ptr<int> sp3(raw_ptr);
    shared_ptr<int> sp4(raw_ptr);
    cout << sp3.use_count() << endl;  // 1
    cout << sp4.use_count() << endl;  // 1
    cout << sp3.get() << endl;        // same address
    cout << sp4.get() << endl;        // same address
}
// ^ Double free runtime error at closing brace.

如果shared_ptrs 都指向同一个东西,为什么use_count() 会返回1(而不是2)?如果use_count() 返回1,那么为什么要尝试释放int 两次?我认为shared_ptr 将增加一个use_count 当且仅当它指向与其兄弟shared_ptrs 相同的地址。

std::shared_ptruse_count 仅由原始指针构造的第一个 shared_ptr 递增(或分配给原始指针,如果默认构造),然后是额外的 shared_ptrs 复制-由任何先前的shared_ptrs 建造或分配?如果有的话,还有哪些其他的递增方式?

【问题讨论】:

  • 试试shared_ptr&lt;int&gt; sp4 = sp3;。您需要复制共享指针对象本身;使用相同的原始指针创建一个新的共享指针仅意味着现在您有两个共享指针,每个共享指针都认为它们拥有对象的独占所有权。如果你改为使用shared_ptr&lt;int&gt; sp3(new int(8));,这会更容易——不要让原始指针在你的程序中可见,以避免意外使用它。
  • 实际上,auto sp3 = std::make_shared&lt;int&gt;(8); 更好,因为这允许 C++ 实现在单个内存分配中为 intshared_ptr 控制块分配空间。 (标准不要求这种优化,但确实允许。如果你使用shared_ptr&lt;int&gt;(new int(8)),那么这种优化是不可能的。)
  • @cdhowie,好点子。我在这里的评论只是为了让其他人更清楚,如果做shared_ptr&lt;int&gt; sp3(new int(8)); shared_ptr&lt;int&gt; sp4(new int(8));sp3sp4 指向不同的ints(在不同的地址),它们只是具有相同的值。

标签: c++ pointers memory-management shared-ptr double-free


【解决方案1】:

当您将指针指向shared_ptr 时,该共享指针将获得该指针的所有权。您不再被允许 delete 它,将其传递给另一个 shared_ptr,或类似的。新的shared_ptr 没有全局查找表来检查是否已经有另一个shared_ptr 已经拥有指针或类似的东西。

换句话说,当第二个shared_ptr 是通过传入相同的指针而不是复制shared_ptr 本身(这会增加使用计数)来创建时,就会发生双重释放错误。直到稍后您才能观察到未定义的行为这一事实并不会改变它实际发生的位置。

【讨论】:

  • 其他shared_ptrs 的复制构造和赋值也是only 方法来增加use_count?
  • @CodeBricks 是的。否则必须有一些原始指针的全局表,以便当您从原始指针构造一个全新的实例时,它可以查找引用计数对象,这需要与多线程程序中的全局表同步。 . 这将是一场噩梦。
  • @codeBricks:唯一不会触发未定义行为的方法,是的。 (有一堆成员函数挂在shared_ptr 上,可能会改变这一点;我并不完全赞成所有事情;但任何其他成员的行为都类似于复制构造或复制分配)
【解决方案2】:

您应该使用 shared_ptr 的复制构造函数来正确构造第二个共享指针。

【讨论】:

    猜你喜欢
    • 2020-01-11
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 2016-07-22
    • 2018-07-30
    • 1970-01-01
    相关资源
    最近更新 更多