【问题标题】:c++ functions using boost::geometry deliver wrong results when compiled with -O2 flag使用 boost::geometry 的 c++ 函数在使用 -O2 标志编译时会提供错误的结果
【发布时间】:2021-11-19 05:05:01
【问题描述】:

我写了一个 c++ 类来执行一些多边形操作(计算两个多边形的最小距离和相交面积)。我用g++ 8.3.0 编译它。在没有 -O2 编译器标志的情况下编译时一切正常。当我使用-O2 标志时,在某些情况下会得到错误的结果(例如,边长为1.0 且位于原点的左下角的两个相等正方形的相交区域是-2.0 而不是预期结果1.0。)

我在另一篇 stackoverflow 帖子中读到,这很可能是因为我的代码中存在内存泄漏或其他错误,而这不太可能是编译器错误。我的代码中是否存在这样的错误?

我尝试了什么:

  • 我仔细检查了boost 的文档,我正确使用了所有函数和类。

  • 我在代码中使用了cppcheck(没有结果)。

  • 我在代码中使用了clang --analyze(没有结果)。

我错过了什么吗?

#include <iostream>
#include <list>
#include <vector>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/multi_point.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>

#include <boost/assign/std/vector.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/assign.hpp>

#include <boost/foreach.hpp>

//#include "ndarray.h"

namespace bg = boost::geometry;

// use the following two commands to compile:
//
//WARNING: DO NOT USE O2. IT DESTROYS bg::correct FUNCTIONALITY
// g++ -lboost_system -c -fPIC polygoncalc.cpp -o polygoncalc.o -O2
// g++ -lboost_system -shared -Wl,-soname,libpolygoncalc.so -o libpolygoncalc.so polygoncalc.o -O2

typedef boost::geometry::model::d2::point_xy<double> point_type;
//typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
typedef bg::model::polygon<point_type> polygon_type;

//typedef std::vector< std::vector<double>> Matrix;

class PolygonCalc{

    public:
        const double helloworld(){
//            std::cout << "Hello World" << std::endl;
            return 0.123;
        }

        double test_calc(){

//            Point points[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)};
//            Point points2[] = {Point(0.5,0.5), Point(1.5,0.5), Point(1.5, 1.5), Point(0.5,1.5)};

            polygon_type poly1 {{{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}}};
            polygon_type poly2 {{{5.5, 0.5}, {6.5, 0.5}, {6.5, 1.5}, {5.5, 1.5}}};

//            polygon_type poly1 {{{0.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, 0.0}, {0.0, 1.0}}};
//            polygon_type poly2 {{{0.5, 1.5}, {1.5, 1.5}, {1.5, 0.5}, {0.5, 0.5}, {0.5, 1.5}}};

            bg::correct(poly1);
            bg::correct(poly2);

//            std::vector<point_type> points1;
//            std::vector<point_type> points2;
//
//            points1.push_back(point_type(0.0,0.0));
//            points1.push_back(point_type(1.0, 0.0));
//            points1.push_back(point_type(1.0, 1.0));
//            points1.push_back(point_type(0.0, 1.0));
//
//            points2.push_back(point_type(0.5, 0.5));
//            points2.push_back(point_type(1.5, 0.5));
//            points2.push_back(point_type(1.5, 1.5));
//            points2.push_back(point_type(0.5, 1.5));

//            boost::geometry::read_wkt(
//                "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3)"
//                    "(4.0 2.0, 4.2 1.4, 4.8 1.9, 4.4 2.2, 4.0 2.0))", poly1);
//
//            boost::geometry::read_wkt(
//                "POLYGON((4.0 -0.5 , 3.5 1.0 , 2.0 1.5 , 3.5 2.0 , 4.0 3.5 , 4.5 2.0 , 6.0 1.5 , 4.5 1.0 , 4.0 -0.5))", poly2);

//            polygon_type poly1;
//            polygon_type poly2;
//
//            bg::assign_points(poly1, points1);
//            bg::assign_points(poly2, points2);

            std::deque<polygon_type> output;
            bg::intersection(poly1, poly2, output);

//            std::cout << bg::area(poly1) <<std::endl;
//            std::cout << bg::area(poly2) <<std::endl;


            double totalArea = 0.0;

            int i = 0;
            BOOST_FOREACH(polygon_type const& p, output)
            {

//                std::cout << i++ << ": " << boost::geometry::area(p) << std::endl;

                totalArea += bg::area(p);
            }

            double d = bg::distance(poly1, poly2);

            std::cout << d << std::endl;

            return totalArea;

        }

        int test_nparray(double *A, int n){

//        int M, N;
//
//        M = poly1.size();
//        N = poly1[0].size();
//
//        std::cout << M << std::endl << N << std::endl;

            int i;
            double sum = 0.0;

            for (i=0; i<n; i++) {

                sum += A[i];

            }

            std::cout << "n: " << n << std::endl;

            std::cout << sum / n << std::endl;

            return n;

        }

        double min_poly_distance(double *poly1x, double *poly1y, double *poly2x, double *poly2y, int m, int n){

            int i;

            std::vector<point_type> points1;
            std::vector<point_type> points2;

            for (i=0; i<m; i++) {
                points1.push_back(point_type(poly1x[i], poly1y[i]));
//                std::cout << poly1x[i] << " " << poly1y[i] << std::endl;
            }

            for (i=0; i<n; i++) {
                points2.push_back(point_type(poly2x[i], poly2y[i]));
            }

            polygon_type poly1;
            polygon_type poly2;

            bg::assign_points(poly1, points1);
            bg::assign_points(poly2, points2);

            bg::correct(poly1);
            bg::correct(poly2);

            std::deque<polygon_type> output;
            bg::intersection(poly1, poly2, output);

            double totalArea = 0.0;

            BOOST_FOREACH(polygon_type const& p, output)
            {
                totalArea += bg::area(p);
            }

            if (totalArea > 0.0){
                return 0.0;
            }

            return bg::distance(poly1, poly2);

        }

        double poly_intersection_area(double *poly1x, double *poly1y, double *poly2x, double *poly2y, int m, int n){

            int i;

            std::vector<point_type> points1;
            std::vector<point_type> points2;

            for (i=0; i<m; i++) {
                points1.push_back(point_type(poly1x[i], poly1y[i]));
//                std::cout << poly1x[i] << " " << poly1y[i] << std::endl;
            }

            for (i=0; i<n; i++) {
                points2.push_back(point_type(poly2x[i], poly2y[i]));
            }

            polygon_type poly1;
            polygon_type poly2;

            bg::assign_points(poly1, points1);
            bg::assign_points(poly2, points2);

            bg::correct(poly1);
            bg::correct(poly2);

            std::deque<polygon_type> output;
            bg::intersection(poly1, poly2, output);

            double totalArea = 0.0;

            BOOST_FOREACH(polygon_type const& p, output)
            {
                totalArea += bg::area(p);
            }

            return totalArea;

        }

        double poly_intersection_area_ratio(double *poly1x, double *poly1y, double *poly2x, double *poly2y, int m, int n){

            int i;

            std::vector<point_type> points1;
            std::vector<point_type> points2;

            for (i=0; i<m; i++) {
                points1.push_back(point_type(poly1x[i], poly1y[i]));
//                std::cout << poly1x[i] << " " << poly1y[i] << std::endl;
            }

            for (i=0; i<n; i++) {
                points2.push_back(point_type(poly2x[i], poly2y[i]));
            }

            polygon_type poly1;
            polygon_type poly2;

            bg::assign_points(poly1, points1);
            bg::assign_points(poly2, points2);

            bg::correct(poly1);
            bg::correct(poly2);

            std::deque<polygon_type> output;
            bg::intersection(poly1, poly2, output);

            double totalArea = 0.0;

            BOOST_FOREACH(polygon_type const& p, output)
            {
                totalArea += bg::area(p);
            }

            double area1 = bg::area(poly1);
            double area2 = bg::area(poly2);

            if (area1 > area2) {

                return totalArea / area2;

            } else {

                return totalArea / area1;

            }

            return totalArea;

        }

};


extern "C" {
    PolygonCalc* PolygonCalc_new(){ return new PolygonCalc; }
    const double PolygonCalc_helloworld(PolygonCalc* polygoncalc){ return polygoncalc->helloworld(); }
    double PolygonCalc_test_calc(PolygonCalc* polygoncalc){ return polygoncalc->test_calc(); }
    int PolygonCalc_test_nparray(double *A, int n, PolygonCalc* polygoncalc){ return polygoncalc->test_nparray(A, n); }
    double PolygonCalc_min_poly_distance(double *poly1x, double *poly1y, double *poly2x, double *poly2y, int m, int n, PolygonCalc* polygoncalc){

        return polygoncalc->min_poly_distance(poly1x, poly1y, poly2x, poly2y, m, n);

    }
    double PolygonCalc_poly_intersection_area(double *poly1x, double *poly1y, double *poly2x, double *poly2y, int m, int n, PolygonCalc* polygoncalc){

        return polygoncalc->poly_intersection_area(poly1x, poly1y, poly2x, poly2y, m, n);

    }
    double PolygonCalc_poly_intersection_area_ratio(double *poly1x, double *poly1y, double *poly2x, double *poly2y, int m, int n, PolygonCalc* polygoncalc){

        return polygoncalc->poly_intersection_area_ratio(poly1x, poly1y, poly2x, poly2y, m, n);

    }
}

【问题讨论】:

    标签: c++ memory-leaks g++ compiler-optimization


    【解决方案1】:

    我解决了这个问题。解决方案是将PolygonCalc *polygoncalc 设为第一个参数而不是最后一个参数(对于extern "C" 部分中的所有函数),并在从python 调用函数时显式提供对象。在另一个 stackoverflow 帖子中,作者没有说明必须将对象作为参数提供,而且在大多数情况下,它似乎确实可以在没有优化的情况下工作。我做了更多研究,看起来-foptimize-sibling-calls 标志是罪魁祸首。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-08
      相关资源
      最近更新 更多