C ++打印树中的shared_ptr使用计数

时间:2019-02-11 02:12:12

标签: c++ shared-ptr

我很难弄清楚为什么当我以不同方式打印树时,共享指针会得到不同数量的use_counts()。

使用下面的代码,当我调用方法“ one-> Print()”时,我似乎错误地获得了1的直接子代的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(one);

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

3 个答案:

答案 0 :(得分:2)

这是因为您使用std::make_shared<Node>(*this)创建了*thisone)的副本,该副本将复制this->childone->chile)并增加了引用柜台。


您想要的可能是从enable_shared_from_this继承并使用shared_from_this,那么您将获得

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

更重要的是,如果不需要引用计数器(通常为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 example

答案 1 :(得分:1)

调用Print(ptr)时,它会作为对共享指针的引用传递,并且不会进行复制。

调用Print()时,它将复制共享指针并将其传递给Print(ptr)

正是该副本增加了引用计数。如果您不希望这种情况发生,请不要进行复制。您应该可以直接通过this作为参考。

答案 2 :(得分:1)

如其他答案所述,通过调用std::make_shared<Node>(*this)实际上是在调用默认副本构造函数。因此,击中某个地方newObj->child = (*this).child(即std :: shared_ptr的重载=(赋值运算符)),从而将引用计数增加到2。当函数Print()退出时,shared_ptr被销毁从而将引用计数减少到1。

致电参考时,什么都没有创建,因此您看到了预期的结果。

解决此问题的一种方法是重载函数以接受const Node &,然后可以使用*this