简体   繁体   中英

How to solve lifetime problems when building a composite object holding pointers to objects is composed by

This question is related to this other one. I'm trying to implement the virtual method approach suggested in one of the answers.

I have an abstract base class representing an object described by a Level-Set function

    class LevelSetObject
    {

    public:
        virtual double SDF(double x, double y, double z) const = 0;


        /** @brief Union of two LevelSetObjects */
        CompositeLevelSetObject operator+(LevelSetObject& other);


        virtual ~LevelSetObject() = default;

    };

The first implementation I had with std::function was working more or less as expected. The difference now is that I return a CompositeLevelSetObject when adding up two generic LevelSetObjects

       CompositeLevelSetObject LevelSetObject::operator+(LevelSetObject& other)  {
            CompositeFun* fun = [] (double sdf_value1, double sdf_value2) {
                return std::min(sdf_value1, sdf_value2);
            };

            auto first = std::unique_ptr<LevelSetObject>(new LevelSetObject(*this));
            auto second = std::unique_ptr<LevelSetObject>(new LevelSetObject(other));

            return { std::move(first), std::move(second), fun };
        }

A CompositeLevelSetObject , at least in my mind :), is an object that takes as input pointers the two objects it's composed by, plus a function pointer that computes the resulting distance function (Primitive combinations of LevelSetObjects are encoded by operations between the two single distance function of the objects ref ("Primitive Combinations") )

    /** @brief This is the function that is called on the two single SDF function of the objects */
    using CompositeFun = double (double, double);


    /**
     * @brief A class representing a composite LevelSetObject coming out of operation between two other LevelSetObjects
     *
     * This class stores pointers to the two LevelSetObject and executes a given function on both of them
     */
    class CompositeLevelSetObject : public LevelSetObject
    {

    using LevelSetObjectPtr = std::unique_ptr<LevelSetObject>;

    private:
        LevelSetObjectPtr m_first;
        LevelSetObjectPtr m_second;
        CompositeFun* m_fun;


    public:
        CompositeLevelSetObject() = default;
        CompositeLevelSetObject(LevelSetObjectPtr first, LevelSetObjectPtr second, CompositeFun* m_fun);
        CompositeLevelSetObject(CompositeLevelSetObject&&);

        double SDF(double x, double y, double z) const override;

        // :: Operators ::
        CompositeLevelSetObject& operator=(CompositeLevelSetObject&&);
    };
}

    double CompositeLevelSetObject::SDF(double x, double y, double z) const {
        return m_fun(m_first->SDF(x, y, z), m_second->SDF(x, y, z));
    }




This clearly does not work, because in the LevelSetObject::operator+ , I'm creating the pointers instantiating an abstract class.

allocating an object of abstract class type 'hgve::LevelSetObject'
            auto first = std::unique_ptr<LevelSetObject>(new LevelSetObject(*this));

So I tried to switch the LevelSetObject::SDF method to be non-pure, returning 0 . But clearly doesn't work because then everything returns 0.

I'm missing something in my conceptual organisation of the data structure, probably due to my dynamic languages background, but I can't see it. Any help is appreciated.

An example of usage:

// Vector containing a list of LevelSetSpheres
static std::vector<LevelSetSphere> elements = {
    LevelSetSphere{radius, {radius, 0.25, 0.25}},
    LevelSetSphere{radius, {radius + interDistance, 0.25, 0.25}},
    LevelSetSphere{radius, {radius + 2*interDistance, 0.25, 0.25}}
};

int main(int argc, char* argv[]) {
    // Sum first two elements
    CompositeLevelSetObject soot = elements[0] + elements[1];
    for(auto el = std::next(elements.begin(), 2); el != elements.end(); ++el) {
        // Combine elements
        soot = soot + *el;
    }
}

LevelSetSphere is a derived class from LevelSetObject .

    class LevelSetSphere : public LevelSetObject
    {
    private:
        double m_R; /**< The radius of the sphere */
        SimpleVector m_C; /**< The center of the sphere */

    public:
        /** @brief Constructor
         *
         *  @param  radius      The radius of the sphere
         */
        LevelSetSphere(double radius, SimpleVector center);

        double SDF(double x, double y, double z) const override;
    };

When you do new LevelSetObject , this creates a new object whose type is LevelSetObject. Seems obvious, but it needs to be pointed out.

You don't want a new LevelSetObject , you want a new LevelSetSphere (if the input object is a sphere).

You can take a LevelSetObject and transfer ownership to a unique_ptr without copying, but you have to be careful with the ownership. If you want to do this, it's better to use a unique_ptr from the start (option 3). You can only transfer ownership if the object was created with new . Local variables, global variables, and elements of vectors (like in your example), among other things, can't be transferred to unique_ptr . Only objects created with new .

Here are three possible solutions:

  1. Add a virtual std::unique_ptr<LevelSetObject> copy() const = 0; method to LevelSetObject . (Implement this in every derived class, so it makes a copy)

  2. Make the CompositeLevelSet object point to the original LevelSetObject s instead of copying them. This means you can't use the composite object after the original objects are destroyed. It also means the intermediate compositions need to be saved somewhere. Not a great option.

  3. Pass ownership into operator+ so that it doesn't need to copy the objects. For example, define a unique_ptr<CompositeLevelSetObject> operator+(unique_ptr<LevelSetObject> left, unique_ptr<LevelSetObject> right) . (If this confuses you, it can be a function instead of an operator)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM