我正在学习C ++,我创建了3个类:NodeEditor,Node,NodeIO。
编辑器本质上包含一个节点向量,每个节点都有一个NodeIO实例的向量。
我希望每个班级都能够引用“所有者”。
NodeIO构造函数基本上从Node接收一个指针,Node接受一个指向编辑器的指针。
class NodeEditor {
NodeEditor() {
...push_back(Node(this));
}
}
class Node {
NodeEditor* owner;
Node(NodeEditor* _owner) : owner{ _owner } {
...push_back(NodeIO(this));
}
}
class NodeIO {
Node* owner;
NodeIO(Node* _owner) : owner{ _owner } { }
}
然后我需要稍后使用_owner
指针。
当我在项目中尝试这个时,首先_owner
指针指向正确的位置,但是一旦我需要稍后检索它,实际的对象就不再存在于该指针位置。
允许这种布局工作的我有哪些选择?在这种情况下,是否会有更多推荐的模式。
答案 0 :(得分:1)
您尚未显示任何复制构造函数。由此,我假设您依赖于编译器提供的默认复制构造函数。这是你问题的根源。
使用时:
NodeEditor
<{1>}中的,您正在存储Node(this)
的副本。但是,如果Node
和NodeIO
没有正确实现的副本构造函数,NodeIO
中Node
对象中的std::vector
个对象将指向{ {1}}无效的对象 - 临时Node
对象。
这是一个显示问题的示例程序。
Node
输出:
#include <iostream>
#include <vector>
struct Node;
struct NodeIO {
Node* owner;
NodeIO(Node* _owner) : owner{ _owner } { }
};
struct NodeEditor;
struct Node {
NodeEditor* owner;
Node(NodeEditor* _owner) : owner(_owner)
{
std::cout << (void*)this << std::endl;
nodeIOList.push_back(NodeIO(this));
nodeIOList.push_back(NodeIO(this));
}
std::vector<NodeIO> nodeIOList;
};
struct NodeEditor {
NodeEditor()
{
nodeList.push_back(Node(this));
nodeList.push_back(Node(this));
}
std::vector<Node> nodeList;
};
int main()
{
NodeEditor editor;
for ( auto& node : editor.nodeList )
{
std::cout << (void*)(&node) << std::endl;
for (auto& nodeIO : node.nodeIOList )
{
std::cout << (void*)(nodeIO.owner) << std::endl;
}
}
}
输出清楚地显示了使用0x7ffe53d34c30
0x7ffe53d34c50
0xae10c0
0x7ffe1af7a2a0
0x7ffe1af7a2a0
0xae10e0
0x7ffe1af7a2c0
0x7ffe1af7a2c0
构造的Node
对象的指针值以及Node(this)
对象的指针值,这些对象存储在{{ 1}}。请注意,Node
对象仍指向临时std::vector<Node>
个对象。它们是NodeIO
中的悬空指针。
我尝试了快速修复,但是没有用。我需要再多做一点。
这是一个适用于默认复制构造函数的解决方案。它使用Node
个main
代替std::vector
个对象。
std::shared_ptr
输出:
std::vector
答案 1 :(得分:1)
向向量添加内容时, all 向量的元素可能会移动。因此,当您添加Node
时,所有现有NodeIO
s&#39;所有者指针无效。
要处理此问题,您需要
Node
副本和移动构造函数,或Node
的移动构造函数中,更新其包含的所有owner
的{{1}}指针,并确保构建新的NodeIO
如果您调用NodeIO
复制构造函数,则正确无误。根据您存储Node
的方式,您应该对它们执行相同操作。
答案 2 :(得分:0)
检查NodeEditor对象和Node Objects和NodeIo对象的生命周期。 使用new运算符创建动态对象,或确保NodeEditor和Node和NodeIo的实例化发生在同一范围内。 检查是否保留了NodeEditor对象的Node容器的副本,并在释放NodeEditor对象后使用它。