Can I somehow return std::optional with const-reference to my data to avoid copy of it?

Viewed 2203

Suppose I have some base class which can optionally return me some specific data. It also provides me 'hasData' function to check if such specific data is available for usage

class MyClassBase {
public:
    virtual bool hasData() const { return false; }
    virtual const Arg1& getData() const { throw std::runtime_error("No data");  }
};

class MyClassDerived: public MyClassBase {
    Arg1 m_data = Arg1(10);
public:
    bool hasData() const override { return true; }
    // Good - no copy constructor for data as I want
    const Arg1& getData() const override { return m_data; }
};

This works well and does what I want. But 'hasData' and 'getData' are good candidates to be replaced by one function returning 'std::optional'. But when I tried to improve API returning std::optional, I realized that I can't return a 'const reference' anymore to my internal data

class MyClassWithOptBase {
public:
    virtual std::optional<Arg1> getData() const { return std::nullopt; }
};

class MyClassWithOptDerived: public MyClassWithOptBase  {
    Arg1 m_data = Arg1(10);
public:
    // Bad - copy constructor is created for my data!
    std::optional<Arg1> getData() const override { return m_data; }

    // std::optional<const Arg1 &> - doesn't compile as references are not allowed
    // const std::optional<Arg1> & - can't return reference to temporary object
};

One possibility is to use std::optional<Arg1> m_data MyClassWithOptDerived - but it doesn't look nice for me - derived class definitely has data and there shall be no reason to store std::optional in it. Also there will be need to move 'm_data' to base class which I definitely don't want

Any other possibility to use std::optional in such example and avoid copying of data?

PS: I checked some articles like std::optional specialization for reference types and seems that it is not possible to avoid copy of data and I probably should live with 'old-style' interface here.

Update: Thank you everyone for such quick responses. Solution that works for me is to use std::reference_wrapper. The solution code will look like

class MyClassWithOptBase {
public:
    virtual std::optional<std::reference_wrapper<const Arg1>> getData() const {
        return std::nullopt;
    }
};

class MyClassWithOptDerived : public MyClassWithOptBase {
    Arg1 m_data = Arg1(10);
public:
    // Good as well - no copy constructor for my data!
    std::optional<std::reference_wrapper<const Arg1>> getData() const override {
        return m_data;
    }
};

// In 'main'
MyClassWithOptDerived opt;
auto res = opt.getData();
//Then res->get() will return me 'const Arg1&' as I want and no copy constructor will be invoked
1 Answers

An optional reference is the same as a pointer. Return const Arg1 *.

Related