我很难弄清楚为什么当我以不同方式打印树时,共享指针会得到不同数量的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)
答案 0 :(得分:2)
这是因为您使用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)
更重要的是,如果不需要引用计数器(通常为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
。