Как работает счетчик декремента умного указателя?

Ниже приведен пример кода для общего указателя. Я определяю общий указатель внутри области фигурных скобок. sp1 инициализируется новым A (счетчик = 1), а sp1 назначается sp2 (копирование и / или назначение увеличивают счетчик на 1, поэтому counter = 2). Я всегда думал, что деструктор A вызывается, когда счетчик становится 0. Но в моем случае, умный указатель, когда вот-вот выйдет из области видимости (через фигурную скобку), счетчик равен двум.

У меня вопрос: кто менял счетчик с 2 на 0?

#include <iostream>
#include <memory>

using namespace std;

class A{
public:
    ~A(){

        std::cout << "~A" <<  std::endl;
    }    
};
int main(){
    {
        shared_ptr<A> sp1 (new A); 
        shared_ptr<A> sp2 = sp1;

        std::cout << "sp1 count = " << sp1.use_count() << std::endl;
        std::cout << "sp2 count = " << sp2.use_count() << std::endl;
    }

return 0;
}

РЕДАКТИРОВАТЬ: ссылка на бумагу на смарт-указатель

выход:


sp1 count = 2

sp2 count = 2

~ A

2 ответа

Решение

Когда ваш код доходит до конца main, деструктор для обоих sp1 а также sp2 run, который уменьшает счетчик до нуля - это ОЧЕНЬ важная часть общих указателей, что деструктор уменьшает счетчик ссылок и, таким образом, когда "ничего" не остается, вызывается деструктор фактического общего объекта.

Разрушитель shared_ptr будет иметь такую ​​логику, как это:

 counter--;    // Should be atomic!
 if (counter == 0)
 {
    delete owned_thing;
 }

Лучшим примером (ИМО) будет что-то вроде этого:

int main()
{
    std::shared_ptr<A> sp1{new A};
    std::cout << "1: sp1.use_count() = " << sp1.use_count() << '\n';

    {
        std::shared_ptr<A> sp2 = sp1;
        std::cout << "2: sp1.use_count() = " << sp1.use_count() << '\n';
        std::cout << "2: sp2.use_count() = " << sp2.use_count() << '\n';
    }

    std::cout << "3: sp1.use_count() = " << sp1.use_count() << '\n';
}

Вывод из этой программы должен быть (используя ваш класс с его деструктором):

1: sp1.use_count () = 1
2: sp1.use_count () = 2
2: sp2.use_count () = 2
3: sp1.use_count () = 1
~ A

Сначала вы создаете общий указатель и инициализируете его, делая счетчик использования 1, Затем вы вводите новую область действия и создаете в ней новый общий указатель, инициализируя его (используя конструктор копирования общих указателей) со старым указателем, что приводит к счету использования обоих указателей. 2, Затем второй общий указатель выходит из области видимости, а деструктор общего указателя уменьшает количество использования на единицу. Наконец, второй общий указатель выходит из области видимости, так как main функция возвращает, и счетчик использования уменьшается на sp1 деструктор. Теперь он достиг нуля, и содержащийся в нем указатель удаляется, что приводит к A деструктор вызывается.

Другие вопросы по тегам