Combining std::unique_ptr and named constructors

235 Views Asked by At

So I am pretty new to C++ and I'm trying to combine std::unique_ptr with a named constructor returning a std::optional. I've got the following structure:

class AbstractClass {
public:
    virtual ~AbstractClass() {}
};

class ChildClassA : public AbstractClass {
public:
    static std::optional<ChildClassA> construct(...) { ... }

private:
    ChildClassA(...) : ...{...} { ... }
};

std::unique_ptr<AbstractClass> construct(...) {
    if (...) {
        return std::make_unique<ChildClassA>(...); // call ChildClassA::construct(...) here
    } else {
        return std::make_unique<ChildClassB>(...); // call ChildClassB::construct(...) here
    }
}

I want to have a function construct() that calls the constructor of one of the child classes depending on some value. The constructors of these child classes may fail, thus I am using named constructors returning an std::optional as described here. construct() should return a std::unique_ptr to make passing of ownership explicit and prevent copying of the constructed object.

Is this possible?

1

There are 1 best solutions below

1
On BEST ANSWER

If your classes are movable then you can move them into the unique_ptr:

#include <optional>
#include <memory>

class AbstractClass {
public:
    virtual ~AbstractClass() {}
};

class ChildClassA : public AbstractClass {
public:
    static std::optional<ChildClassA> construct();

private:
    ChildClassA(){}
};

class ChildClassB : public AbstractClass {
public:
    static std::optional<ChildClassB> construct();

private:
    ChildClassB(){}
};

std::unique_ptr<AbstractClass> construct(bool a) {
    if (a) {
        auto temp = ChildClassA::construct();
        if (temp) {
            return std::make_unique<ChildClassA>(std::move(*temp));
        }
        return {};
    } else {
        auto temp = ChildClassB::construct();
        if (temp) {
            return std::make_unique<ChildClassB>(std::move(*temp));
        }
        return {};
    }
}

However a possibly null unique_ptr would be much simpler for this usecase:

#include <optional>
#include <memory>

class AbstractClass {
public:
    virtual ~AbstractClass() {}
};

class ChildClassA : public AbstractClass {
public:
    static std::unique_ptr<ChildClassA> construct();

private:
    ChildClassA(){}
};

class ChildClassB : public AbstractClass {
public:
    static std::unique_ptr<ChildClassB> construct();

private:
    ChildClassB(){}
};

std::unique_ptr<AbstractClass> construct(bool a) {
    if (a) {
        return ChildClassA::construct();
    } else {
        return ChildClassB::construct();
    }
}