1

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?

bit4fox
  • 2,021
  • 2
  • 13
  • 8

1 Answers1

2

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();
    }
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • I'd extract the `optional` -> `unique_ptr` thing into its own function (possibly with a `Args&& ... args` + forwarding incantation) to improve this answer (e.g. https://godbolt.org/z/Y2xcF7) but overall this is also the solution I would recommend under these constraints. – Max Langhof Dec 03 '19 at 15:42