C shared_from_это() не позволяет объекту разрушаться

#c #c 11 #visual-c #c 17 #c 14

Вопрос:

У меня есть следующий фрагмент кода, который создает простой объект с именем, а внутри него создает другое имя объекта со shared_from_this() ссылкой. Как я читаю отсюда https://en.cppreference.com/w/cpp/memory/enable_shared_from_this/shared_from_this

«Эффективно выполняет std::shared_ptr(weak_this), где weak_this является частным изменяемым членом std::weak_ptr для enable_shared_from_this».

Что я понимаю как shared_from_this (), только создает слабый указатель на общий объект. Но я не вижу, чтобы это имело место во время выполнения. Фактически создается циклическая ссылка.

В конце я ожидал, что имя obj должно быть уничтожено, но это не так, потому что счетчик ссылок равен 2.

Может ли кто-нибудь помочь мне понять , как я должен использовать enable_shared_from_this() , чтобы эффективно очистить имя obj, как только оно выйдет из ссылки.

 #include <iostream>
#include <memory>
#include <string>
#include <chrono>
#include <thread>

using namespace std;

struct Another;
struct Name : public std::enable_shared_from_this<Name> {
    std::string t;
    int m, n, p;
    shared_ptr<Another> ann;
    Name() {
        std::cout << "constructorn";
    }
    void MakeSomething() {
        ann = std::make_shared<Another>(shared_from_this());
    }
    ~Name() {
        std::cout << "destructorn";
    }
};

struct Another {
    shared_ptr<Name> nn;
    Another(shared_ptr<Name> n) : nn(n) {
        std::cout << "from another constructor " << nn.use_count() << "n";
    }
    ~Another() {
        std::cout << "from another destructorn";
    }
};

int main()
{
    {
        auto n = std::make_shared<Name>();
        std::cout << "Name ref count so far: " << n.use_count() << "n";

        auto p = n.get();
        //delete p;
        std::cout << "Name ref count so far: " << n.use_count() << "n";

        n->MakeSomething();
        std::cout << "Name ref count so far: " << n.use_count() << "n";
        {
            shared_ptr<Name> m = n;
            std::cout << "Name ref count so far: " << n.use_count() << "n";
        }

        std::cout << "Name ref count so far: " << n.use_count() << "n";
    }
    // problem: at this point Name obj, should go out of reference and destructor to be called, which is NOT happening

    return 0;
}
 

А вот результат выполнения (компилятор использовал msvc)

 constructor
Name ref count so far: 1
Name ref count so far: 1
from another constructor 3
Name ref count so far: 2
Name ref count so far: 3
Name ref count so far: 2
 

Комментарии:

1. У вас есть циклическая ссылка на shared_ptrs. Они никогда не выходят за рамки, потому что указывают друг на друга.

2. @Yksisarvinen да, я знаю об этом. shared_from_this создает циклическую ссылку, когда в документации говорится, что она создает слабую ссылку. Каким должен быть правильный способ использования shared_from_this

3. Вероятно, вам нужно, чтобы один из них использовал std::weak_ptr

4. Это не имеет к этому никакого отношения shared_from_this . У вас есть две shared_ptr буквы «с», обе указывают друг на друга. Они не могут освободиться сами по себе, потому что никогда не бывает момента, когда либо заканчивается срок их жизни. Вам нужно будет отпустить ( reset() ) один из них вручную, чтобы разорвать круг. Или один из них должен быть не a shared_ptr , а a weak_ptr или необработанный указатель, не являющийся владельцем.

5. » shared_from_this создает круговую ссылку» — нет, это вы создали круговую ссылку. Если функция shared_from_this вызывается изолированно (не назначается чему-либо), она возвращает временный объект, который немедленно уничтожается. Для ann создания круговой ссылки требуются ваши и nn участники. Все shared_from_this , что было сделано, — это упрощение кода, создающего циклическую ссылку; это не является существенной частью этого кода.

Ответ №1:

Что я понимаю как shared_from_this (), только создает слабый указатель на общий объект. Но я не вижу, чтобы это имело место во время выполнения. Фактически создается циклическая ссылка.

shared_from_this() это создание weak_ptr , которое вы передаете shared_ptr конструктору, как указано в (11) здесь. Этот конструктор создает a shared_ptr для того же объекта, увеличивая количество ссылок.

Также имейте в виду, что weak_ptr это вообще не влияет на количество ссылок, поэтому это не имеет никакого отношения к вашей путанице с количеством ссылок. Сосредоточьтесь на том, что shared_ptr делают s.