Boost Geometry中值返回多边形对象原地迭代时首元素出现垃圾值的问题咨询
Boost Geometry中值返回多边形对象原地迭代时首元素出现垃圾值的问题咨询
我最近在项目中集成Boost Geometry时遇到了一个奇怪的问题:当从自定义类中返回多边形几何对象并直接原地迭代其外层点集时,第一个点会出现垃圾值,但如果先把返回的多边形存到本地变量再迭代就一切正常。以下是我复现问题的最小示例和相关疑问:
复现代码
头文件 shape.hpp
#pragma once #include <boost/geometry.hpp> #include <boost/geometry/geometries/point_xy.hpp> #include <boost/geometry/geometries/polygon.hpp> #include <boost/version.hpp> using my_point_t = boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian>; using my_polygon_t = boost::geometry::model::polygon<my_point_t>; class Shape { private: my_polygon_t polygon_; public: Shape() = default; Shape(const std::vector<my_point_t>& poly){ for (const auto& pt : poly) { polygon_.outer().push_back(pt); } // Close the polygon by adding the first point again if (!polygon_.outer().empty()) { polygon_.outer().push_back(polygon_.outer().front()); } } my_polygon_t getPolygon() const { return polygon_; } };
有问题的 main.cpp
#include <iostream> #include "shape.hpp" int main() { std::cout << BOOST_LIB_VERSION << std::endl; // Or BOOST_VERSION std::vector<my_point_t> my_points; my_points.push_back({0.0, 0.0}); my_points.push_back({0.0, 10.0}); my_points.push_back({10.0, 10.0}); my_points.push_back({10.0, 0.0}); Shape shape = Shape(my_points); for (my_point_t pt : shape.getPolygon().outer()) { std::cout << "x: " << boost::geometry::get<0>(pt) << ", y: " << boost::geometry::get<1>(pt) << '\n'; } return 0; }
有问题的输出
1_74 -> Version of Boost Geometry x: 1.30295e-313, y: 1.23525e-76 x: 0, y: 10 x: 10, y: 10 x: 10, y: 0 x: 0, y: 0
修正后的 main.cpp
#include <iostream> #include "shape.hpp" int main() { std::cout << BOOST_LIB_VERSION << std::endl; // Or BOOST_VERSION std::vector<my_point_t> my_points; my_points.push_back({0.0, 0.0}); my_points.push_back({0.0, 10.0}); my_points.push_back({10.0, 10.0}); my_points.push_back({10.0, 0.0}); Shape shape = Shape(my_points); auto result = shape.getPolygon(); for (my_point_t pt : result.outer()) { std::cout << "x: " << boost::geometry::get<0>(pt) << ", y: " << boost::geometry::get<1>(pt) << '\n'; } return 0; }
正确的输出
1_74 -> Version of Boost Geometry x: 0, y: 0 x: 0, y: 10 x: 10, y: 10 x: 10, y: 0 x: 0, y: 0
我的疑问
我原本理解返回值会在整个循环的生命周期内保持有效,但实际情况却出现了悬空引用导致的未定义行为。想请教这是我对C++临时对象生命周期的理解有误,还是Boost Geometry的实现存在问题?
问题原因分析
这并不是Boost Geometry的bug,而是C++临时对象生命周期与引用结合时的常见陷阱:
shape.getPolygon()返回的是一个临时的my_polygon_t对象,这个临时对象的生命周期仅在创建它的表达式中有效。outer()方法返回的是该多边形对象内部外层容器的引用。在有问题的循环中,范围for循环迭代的是这个引用指向的容器,但临时的多边形对象在表达式shape.getPolygon().outer()结束后就会被销毁,导致引用悬空,访问的是已经被释放的内存空间,因此出现垃圾值(后续元素可能未被覆盖属于未定义行为,不能依赖)。- 当将返回值存储到本地变量
result时,result的生命周期覆盖整个循环过程,outer()返回的引用指向的是result内部的有效容器,因此访问完全正常。
解决方案
方案1:显式存储临时对象(已验证有效)
像你已经尝试的那样,先将getPolygon()的返回值存储到一个本地变量,确保其生命周期覆盖整个迭代过程,避免引用悬空。
方案2:修改getPolygon返回常量引用
如果不需要返回多边形的副本,可以修改Shape类的getPolygon方法,返回常量引用而非值:
const my_polygon_t& getPolygon() const { return polygon_; }
这样shape.getPolygon().outer()返回的引用指向的是shape对象内部的polygon_,而shape在循环期间始终有效,因此不会出现悬空引用问题,原有的有问题的main.cpp代码也能正常运行。
注意:使用这个方案时,要确保Shape对象的生命周期不短于迭代过程,避免出现新的悬空引用。
内容来源于stack exchange




