我可以以某种方式返回 std::Optional 并带有对我的数据的 const 引用以避免复制它吗?

Mic*_*sov 5 c++ stl c++17 stdoptional

假设我有一些基类,它可以选择返回一些特定的数据。它还为我提供了“hasData”函数来检查此类特定数据是否可供使用

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; }
};
Run Code Online (Sandbox Code Playgroud)

这效果很好并且达到了我想要的效果。但是“hasData”和“getData”是很好的候选者,可以用一个返回“std::optional”的函数来替换。但是当我尝试改进返回 std::Optional 的 API 时,我意识到我无法再将“常量引用”返回到我的内部数据

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
};
Run Code Online (Sandbox Code Playgroud)

一种可能性是使用std::optional<Arg1> m_dataMyClassWithOptDerived - 但它对我来说看起来不太好 - 派生类肯定有数据,并且没有理由在其中存储 std::Optional 。另外还需要将“m_data”移动到我绝对不想要的基类

在这样的示例中使用 std::Optional 并避免复制数据的其他可能性吗?

PS:我检查了一些文章,例如引用类型的 std::optical 专业化,似乎不可能避免数据复制,我可能应该在这里使用“旧式”界面。

更新: 感谢大家如此快速的回复。对我有用的解决方案是使用 std::reference_wrapper。解决方案代码如下所示

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
Run Code Online (Sandbox Code Playgroud)

Cal*_*eth 3

可选引用与指针相同。返回const Arg1 *

  • 但是,_未定义行为_(可能无效的指针解除引用)和_抛出异常_之间存在差异。 (2认同)