c++ - 返回一个weak_ptr 成员变量
问题描述
我有以下TreeNode
类,它可以存储对其父节点的引用以及指向其所有子节点的指针向量。
树节点
class TreeNode : public std::enable_shared_from_this<TreeNode>
{
private:
int val_;
std::weak_ptr<TreeNode> parent_;
std::vector<std::shared_ptr<TreeNode>> children_;
public:
TreeNode(int val) : val_(val) {}
void addChild(std::shared_ptr<TreeNode> child)
{
child->parent_ = shared_from_this();
children_.push_back(std::move(child));
}
const int& getVal() const
{
return val_;
}
std::weak_ptr<TreeNode> getParent()
{
return parent_;
}
};
parent_
存储为 a以便在weak_ptr
父级与其子级之间没有循环依赖/内存泄漏。
主要的
int main(int argc, char** argv) {
std::shared_ptr<TreeNode> parent = std::make_shared<TreeNode>(1);
std::shared_ptr<TreeNode> child = std::make_shared<TreeNode>(2);
parent->addChild(child);
// child->getParent()->getVal(); not possible
return 0;
}
使用此类时,我想访问任何节点的父节点的值(...否则为什么要存储父节点),但是由于parent_
是 a weak_ptr
,因此我不能在其上调用任何成员函数。
我知道这方面有一些“黑客”,比如使用从 alock
中提取,但我觉得这使 API 变得笨拙。我想知道返回 a 的推荐 C++11 方式是什么,它仍然可以使用。shared_ptr
weak_ptr
weak_ptr
编辑:
从 API 的角度来看,我可能不应该称之为lock
“hack”,而是不优雅。
例如,如果我想访问parent_
我将不得不做这样的事情
主要的
if (!child->getParent()->expired())
{
std::cout << child->getParent()->lock()->getVal() << std::endl;
}
这似乎相当冗长,所以我想知道是否有任何语言功能我可以利用来避免做所有这些。
解决方案
lock
调用a是没有办法的weak_ptr
,关键weak_ptr
在于它不计入它所指向的对象的引用计数,同时仍然允许使用控制块来检查对象是否有效,并且然后得到一个shared_ptr
.
对我来说,它看起来parent_
不应该是一个weak_ptr
,而是一个原始指针。使用原始指针不是坏习惯或“不现代”,它们只是不应该拥有任何内存。有了它,您可以检查它是否是一个nullptr
,以检查一个节点是否有父节点。
您在 a 上使用的示例lock
也是weak_ptr
错误的。shared_ptr
并且weak_ptr
被许多线程同时创建和销毁,这就是它们的大多数用例所在。
if (!child->getParent()->expired())
{
std::cout << child->getParent()->lock()->getVal() << std::endl;
}
在您的示例中,您首先使用成员函数检查指针是否仍然有效expired
,如果它是您lock
用来获取shared_ptr
将有助于对象引用计数的指针。如果有多个线程可能正在使用该指针,那么在调用之后expired
和lock
调用之前,您的引用计数可能会达到 0,并且可以从内存中删除对象。然后,当您取消引用它时,您将获得一个nullptr shared_ptr
fromlock
和未定义的行为。
如果您继续使用weak_ptr
,请这样做。
if(auto parent_ptr = child->getParent()->lock())
{
// parent_ptr is shared_ptr that is not null here
}
推荐阅读
- java - 如何在 Java Poet 中添加函数的参数化返回类型
- nutch - Nutch 任何人都可以解释 readdb stats 中的状态名称是什么
- android - 调用 Handler.sendEmptyMessageDelayed(int, long) 时出现 NullPointerException
- javascript - 更改第一个对象中的值会导致第二个对象更改
- ios - 使用经典 BT 和 BLE 与同一外围设备通信时出现“对等删除配对信息”错误
- python - 如何在两个限制之间整合一个数组
- c# - 实体框架 DateTime 具有毫秒差异,而数据保留在数据库中
- python - 从具有特定模式的字符串中获取子字符串
- javascript - 我在哪里把我的配置放在这个 axios 请求中?
- python - 拆分字符串直到第一次遇到数字和“:”