创建临时文件时 std::function 内存访问错误

2022-01-12 00:00:00 geometry segmentation-fault c++ c++11

我目前正在实现一些抽象来表示 3D 对象的水平集操作.基本上是在 this GLSL 着色器的惊人页面中描述的内容.

I'm currently implementing few abstractions to represent level-set operations for 3D objects. Basically what is described in this amazing page for GLSL shaders.

为了简要概述,可以通过将 R^3 域映射到称为水平集(或有符号距离函数)的标量的函数来描述 3D 对象.例如,对于一个球体,水平集函数由 phi(X) = X.Norm2() - R*R 定义,其中 Norm2 表示平方欧几里得范数R^3 中的向量.

To give a brief overview, a 3D object can be described by a function that maps the R^3 domain to a scalar called level-set (or signed-distance-function). For example, for a sphere, the level-set function is defined by phi(X) = X.Norm2() - R*R where Norm2 represents the squared Euclidean norm of a vector in R^3.

于是我想出了一个代表这样一个概念的LevelSetObject类:

So I came out with a LevelSetObject class that represents such a concept:

 class LevelSetObject
    {

    using SDFFunction = std::function<double(double, double, double)>;

    protected:
        SDFFunction m_SDF;

    public:

        double SDF(double x, double y, double z) const {
            return m_SDF(x, y, z);
        }

现在我想在 LevelSetObject 之间定义几个运算符.例如 union 运算符:

Now I wanted to define few operators between LevelSetObjects. For example the union operator:

LevelSetObject LevelSetObject::operator+(const LevelSetObject& other) const {
        LevelSetObject outObj;
        outObj.m_SDF = [this, other]
            (double x, double y, double z) {
                return std::min(m_SDF(x, y, z), other.m_SDF(x, y, z));
            };
        return outObj;
    }

但是,当我创建一个临时对象时,我遇到了糟糕的内存访问,例如,由于三重总和(而如果我在评论的情况下分别对两个对象求和,则使用 Valgrind 而不是 SIGSEV 不会发现内存泄漏).LevelSetSphereLevelSetObject 的派生类,我在其中专门定义了球体的 SDF(给定它的 center 及其 radius)

But I'm experiencing bad memory access when I create a temporary due to, for example, a triple sum (while if I sum the two objects separately as in the commented case, no memory leak is spotted using Valgrind and not SIGSEV). LevelSetSphere is a derived class of LevelSetObject where I define specifically the SDF of a sphere (given its center and its radius)

int main(int argc, char* argv[]) {

    // Generate the central sphere
    double radius = 1.0;
    SimpleVector center(2, 2, 2);
    LevelSetSphere sphere(radius, center);

    // Generate the ears spheres
    LevelSetSphere ear1(radius/2, SimpleVector(1, 1, 2));
    LevelSetSphere ear2(radius/2, SimpleVector(3, 1, 2));

    // Combine objects
    auto mickeyMouse = sphere + ear1 + ear2;
    //auto first = sphere + ear1;
    //auto mickeyMouse = first + ear2;

    // Materialize in the domain

    mickeyMouse.SDF(0.0, 0.0, 0.0);



}

我想在 operator+ 定义中, std::function 保留对 other 的引用,当我实际上调用 m_SDF 因为在三重和期间创建了一个临时文件.我也试过把operator+的签名改成operator+(const LevelSetObject other),这样通过copy,结果还是一样的.

What I suppose is that in the operator+ definition, the std::function keeps a reference to other that becomes a dangling reference when I actually call m_SDF because a temporary is created during the triple sum. I also tried to change the signature of operator+ to operator+(const LevelSetObject other), so passing by copy, but the outcome is the same.

我在哪里失败了?:)

推荐答案

你的错误内存访问不是由于 other 变量,而是 this 的指针临时对象超出范围.

Your bad memory access isn't due to the other variable, it's the this pointer of the temp object going out of scope.

您可以通过显式捕获 SDF 变量来修复它,如下所示:

You can fix it by capturing the SDF variables explicitly, like this:

LevelSetObject LevelSetObject::operator+(const LevelSetObject& other) const {
        LevelSetObject outObj;
        auto& SDF=this->m_SDF;
        auto& other_SDF=other.m_SDF
        outObj.m_SDF = [SDF, other_SDF]
            (double x, double y, double z) {
                return std::min(SDF(x, y, z), other_SDF(x, y, z));
            };
        return outObj;
    }

相关文章