返回一个 weak_ptr 成员变量
Returning a weak_ptr member variable
我有以下 TreeNode
class,它可以存储对其父节点的引用以及指向其所有子节点的指针向量。
树节点
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_
存储为 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;
}
使用此 class 时,我想访问任何节点的父节点的值(...否则为什么要存储父节点),但由于 parent_
是 weak_ptr
, 我不能在上面调用任何成员函数。
我知道有一些 "hacks" 围绕着这个,比如使用 lock
从 weak_ptr
中提取 shared_ptr
,但我觉得这使得 [=55= 】 笨重。我想知道返回 weak_ptr
的推荐 C++11 方法是什么,它仍然可用。
编辑:
我可能不应该将 lock
称为 "hack",但从 API 的角度来看相当不优雅。
例如,如果我想访问 parent_
,我将不得不做这样的事情
主要
if (!child->getParent()->expired())
{
std::cout << child->getParent()->lock()->getVal() << std::endl;
}
这似乎相当冗长,所以我想知道是否有任何语言功能可以利用来避免执行所有这些操作。
没有办法在 weak_ptr
上调用 lock
,weak_ptr
的全部意义在于它不计入它指向的对象的引用计数,同时仍然允许使用控制块来检查对象是否有效,然后得到一个 shared_ptr
.
对我来说 parent_
不应该是 weak_ptr
,而是原始指针。使用原始指针不是坏习惯或 'not modern',它们只是不应该拥有任何内存。有了它,您可以检查它是否是 nullptr
或不是,以检查节点是否有父节点。
您在 weak_ptr
上使用 lock
的示例也是错误的。 shared_ptr
和 weak_ptr
由许多线程同时创建和销毁,这就是它们的大部分用例。
if (!child->getParent()->expired())
{
std::cout << child->getParent()->lock()->getVal() << std::endl;
}
在您的示例中,您首先使用 expired
成员函数检查指针是否仍然有效,如果是,您使用 lock
获取将有助于对象的 shared_ptr
参考计数。如果有多个线程可能正在使用该指针,则在您的 expired
调用之后和 lock
调用之前,您的引用计数可能会达到 0,并且对象可能会从内存中删除。然后你会从 lock
得到一个 nullptr shared_ptr
,当你取消引用它时会出现未定义的行为。
如果您继续使用 weak_ptr
,请这样做。
if(auto parent_ptr = child->getParent()->lock())
{
// parent_ptr is shared_ptr that is not null here
}
我有以下 TreeNode
class,它可以存储对其父节点的引用以及指向其所有子节点的指针向量。
树节点
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_
存储为 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;
}
使用此 class 时,我想访问任何节点的父节点的值(...否则为什么要存储父节点),但由于 parent_
是 weak_ptr
, 我不能在上面调用任何成员函数。
我知道有一些 "hacks" 围绕着这个,比如使用 lock
从 weak_ptr
中提取 shared_ptr
,但我觉得这使得 [=55= 】 笨重。我想知道返回 weak_ptr
的推荐 C++11 方法是什么,它仍然可用。
编辑:
我可能不应该将 lock
称为 "hack",但从 API 的角度来看相当不优雅。
例如,如果我想访问 parent_
,我将不得不做这样的事情
主要
if (!child->getParent()->expired())
{
std::cout << child->getParent()->lock()->getVal() << std::endl;
}
这似乎相当冗长,所以我想知道是否有任何语言功能可以利用来避免执行所有这些操作。
没有办法在 weak_ptr
上调用 lock
,weak_ptr
的全部意义在于它不计入它指向的对象的引用计数,同时仍然允许使用控制块来检查对象是否有效,然后得到一个 shared_ptr
.
对我来说 parent_
不应该是 weak_ptr
,而是原始指针。使用原始指针不是坏习惯或 'not modern',它们只是不应该拥有任何内存。有了它,您可以检查它是否是 nullptr
或不是,以检查节点是否有父节点。
您在 weak_ptr
上使用 lock
的示例也是错误的。 shared_ptr
和 weak_ptr
由许多线程同时创建和销毁,这就是它们的大部分用例。
if (!child->getParent()->expired())
{
std::cout << child->getParent()->lock()->getVal() << std::endl;
}
在您的示例中,您首先使用 expired
成员函数检查指针是否仍然有效,如果是,您使用 lock
获取将有助于对象的 shared_ptr
参考计数。如果有多个线程可能正在使用该指针,则在您的 expired
调用之后和 lock
调用之前,您的引用计数可能会达到 0,并且对象可能会从内存中删除。然后你会从 lock
得到一个 nullptr shared_ptr
,当你取消引用它时会出现未定义的行为。
如果您继续使用 weak_ptr
,请这样做。
if(auto parent_ptr = child->getParent()->lock())
{
// parent_ptr is shared_ptr that is not null here
}