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

C++ Printing shared_ptr use count in tree

本文关键字:打印 shared ptr C++      更新时间:2023-10-16

我很难弄清楚为什么当我以不同的方式打印树时,我的共享指针会得到不同数量的 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->打印((;

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

一>打印(一(;

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

这是因为您使用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)

更重要的是,如果你

不需要引用计数器(通常是真的(,如果你不打算管理资源,你不需要智能指针,你可以简单地接受一个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(,魔杖盒示例

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

当您调用 Print() 时,它会创建共享指针的副本并将其传递给Print(ptr)

正是该副本增加了引用计数。如果您不希望发生这种情况,请不要复制。您应该能够直接传递this作为参考。

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

当您使用引用调用时,不会创建任何内容,因此您会看到预期的结果。

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