C ++ Печать shared_ptr использовать счетчик в дереве - PullRequest
0 голосов
/ 11 февраля 2019

Мне сложно понять, почему, когда я печатаю дерево разными способами, я получаю разные числа use_counts () для моих общих указателей.

Используя приведенный ниже код, когда я вызываю метод "one-> Print () ", я, кажется, неправильно получаю 2 ссылки для непосредственного потомка одного, но при использовании" one-> Print (one) "я получаю правильное количество ссылок, которое равно 1.

Как я могу изменить свой код, чтобы "one-> Print ()" возвращал правильное количество ссылок для всех узлов в дереве?

#include <iostream>
#include <memory>

template<class T> using sp = std::shared_ptr<T>;

struct Node {

    int value; 
    sp<Node> child;
    Node(int value): value {value} {}

    inline void Print() const {
        Print(std::make_shared<Node>(*this));
    }

    inline void Print(const sp<Node>& ptr) const {
        Print(ptr, "", false);
    }

    void Print(const sp<Node>& ptr, const std::string& prepend, bool isEnd) const {
        if(ptr != nullptr) {
            std::cout << prepend << (isEnd ? "└────" : "├────"); 
            std::cout << " " << ptr->value << " (" << ptr.use_count() << ")" << std::endl;
        } else {
            std::cout << " " << ptr->value << std::endl;
        }
        if(ptr->child != nullptr) {
            Print(ptr->child, prepend + (isEnd ? "     " : "│     "), false); 
        }
    }

};

int main(int argc, char * argv[])
{
    sp<Node> one = std::make_shared<Node>(1);
    one->child = std::make_shared<Node>(2); 
    one->child->child = std::make_shared<Node>(3);
    one->child->child->child = std::make_shared<Node>(4);
    one->child->child->child = std::make_shared<Node>(5);

    one->Print(); 

    one->Print(one);

    return 0;
}

Вывод выглядит так:

one-> Print ();

├──── 1 (1)
│     └──── 2 (2)
│          └──── 3 (1)
│               └──── 5 (1)

one-> Print (один);

├──── 1 (1)
│     └──── 2 (1)
│          └──── 3 (1)
│               └──── 5 (1)

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

это потому, что вы используете std::make_shared<Node>(*this), который создает копию *this (one), которая будет копировать this->child (one->chile) и увеличивать счетчик ссылок.


то, что вы хотите - это, вероятно, наследовать от enable_shared_from_this и использовать shared_from_this, тогда вы получите

├──── 1 (2)
│     └──── 2 (1)
│          └──── 3 (1)
│               └──── 5 (1)

более того, если вам не нужна ссылкаcounter (обычно true), вам не нужен умный указатель, если вы не собираетесь управлять ресурсом, вы можете просто принять Node*.На самом деле, вы можете использовать this и удалить все указатели в этом примере.


пример кода.(используйте this вместо ptr)

struct Node: std::enable_shared_from_this<Node> {

    int value; 
    sp<Node> child;
    Node(int value): value {value} {}

    void Print() const {
        Print("", false);
    }

    void Print(const std::string& prepend, bool isEnd) const {
        std::cout << prepend << (isEnd ? "└────" : "├────"); 
        std::cout << " " << this->value << " (" << shared_from_this().use_count()-1 /*remove current count*/ << ")" << std::endl;
        if(this->child) {
            this->child->Print(prepend + (isEnd ? "     " : "│     "), false); 
        }
    }

};

Вы также можете использовать week_from_this (c ++ 17), пример wandbox

0 голосов
/ 11 февраля 2019

Как упоминалось в других ответах, вызывая std::make_shared<Node>(*this), вы фактически вызываете конструктор копирования по умолчанию.Таким образом, ударяя куда-нибудь newObj->child = (*this).child (i, e - перегруженный = (оператор присваивания) для std :: shared_ptr), таким образом увеличивая счетчик ссылок до 2. Когда функция Print() выходит, shared_ptr уничтожается и, таким образом, сокращаетсяref count to 1.

Когда вы звоните со ссылкой, ничего не создается, и, таким образом, вы видите ожидаемые результаты.

Один из способов решения этой проблемы - перегрузить вашу функцию для принятия const Node & и тогда вы можете использовать *this.

0 голосов
/ 11 февраля 2019

Когда вы вызываете Print(ptr), он передается как ссылка на общий указатель, и копия не создается.

Когда вы вызываете Print(), он создает копию общего указателя и передает ееPrint(ptr).

Это та копия, которая увеличивает счетчик ссылок.Если вы не хотите, чтобы это произошло, не делайте копию.Вы должны быть в состоянии передать this непосредственно в качестве ссылки.

...