我有一些这样的代码
std::vector<cuarl_path::Path> RoverPlanner::get_paths(const char *filename) const
{
pugi::xml_document doc;
doc.load_file(filename);
pugi::xml_node root = doc.document_element();
std::vector<cuarl_path::Path> paths;
for (auto path_node : root.children()) {
std::vector<cuarl_path::Segment*> segments;
for (auto segment_node : path_node.children())
{
//do stuff to populate the `segments` vector
}
cuarl_path::Path* path = new cuarl_path::Path(segments);
paths.push_back(*path); //Path destructor called here
}
return paths;
}
问题似乎是std :: vector“路径”调用了它的析构函数,但是我不明白为什么。范围尚未结束。
paths.push_back(*path);
这会做一些事情。
它Path
从堆分配的*path
对象构造一个副本。
它调整paths
向量的大小。有时这可能只涉及增加一个整数,但有时它涉及移动每个现有Path
对象并销毁旧对象。
首先,您有漏洞。new
在免费存储区上分配对象,您将始终负责确保将其清除。将对象从免费存储中复制到向量中不会清除免费存储中的对象。
第二点,vector
实际上是持有实际对象,而不是对它们的引用。因此,当您调整缓冲区的大小(push_back
可以这样做)时,必须四处移动对象的值,然后清理要丢弃的对象。
清理是您正在执行的析构函数。
您似乎是C#或Java程序员。在这两种语言中,都很难创建对象的实际值,它们想保留垃圾回收的对象引用。对象数组实际上是这些语言中对对象的引用的数组。在C ++中,对象向量是实际上包含所讨论对象的向量。
您的使用new
也是一个提示。不需要new
那里,也不需要指针:
std::vector<cuarl_path::Path> RoverPlanner::get_paths(const char *filename) const
{
pugi::xml_document doc;
doc.load_file(filename);
pugi::xml_node root = doc.document_element();
std::vector<cuarl_path::Path> paths;
for (auto&& path_node : root.children()) {
std::vector<cuarl_path::Segment*> segments;
for (auto segment_node : path_node.children())
{
//do stuff to populate the `segments` vector
}
cuarl_path::Path path = cuarl_path::Path(segments);
paths.push_back(std::move(path)); //Path destructor called here
}
return paths;
}
您仍然会在行上调用路径析构函数(实际上,您会得到一个额外的),但是您的代码不会泄漏。假设您的move构造函数正确(并且实际上正确地移动了路径的状态),那么一切都会正常。
现在,一个更高效的版本如下所示:
std::vector<cuarl_path::Path> RoverPlanner::get_paths(const char *filename) const
{
pugi::xml_document doc;
doc.load_file(filename);
pugi::xml_node root = doc.document_element();
std::vector<cuarl_path::Path> paths;
auto&& children = root.children();
paths.reserve(children.size());
for (auto path_node : children) {
std::vector<cuarl_path::Segment*> segments;
for (auto segment_node : path_node.children())
{
//do stuff to populate the `segments` vector
}
paths.emplace_back(std::move(segments));
}
return paths;
}
它将摆脱您正在使用的所有临时变量,并在不再使用它们时移动资源。
假设使用有效的move构造函数,则最大的好处是我们预先重新分配了路径向量(节省lg(n)内存分配),并将段向量移入路径的构造函数中(如果写得正确,可以避免不必要的复制)段指针缓冲区的大小)。
此版本也没有在相关行上调用析构函数,但我认为这不是特别重要;空路径的析构函数的成本应该几乎是免费的,甚至可以合理地消除。
我还可能避免了该path_node
对象的副本,这取决于它的编写方式,值得避免。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句