3

Can I return a const reference argument from a function in C++? I.e., does this code lead to undefined behavior?

template<typename T>
class Option {
public:
    ...

    const T & getOrElse(const T &x) const
    {
        return val == nullptr ? x : *val;
    }

private:
    T *val = nullptr;
}

Option<Foo> foo;
foo.getOrElse(Foo());  // <- using a temporary `Foo`
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Zizheng Tai
  • 6,170
  • 28
  • 79
  • Depends of the lifetime of `x`, but potentially, yes. Is [this](https://stackoverflow.com/questions/14735630/which-standard-wording-tells-us-that-ref-to-const-temporary-lifetime-extension-o) what you are looking for? Otherwise, please clarify the question with a [mcve]. – Baum mit Augen May 03 '16 at 00:07
  • Ok, the lifetime issue for `x` is resolved, so as explained in the question I linked, the function returns a dangling reference and using it would be UB, yes. – Baum mit Augen May 03 '16 at 00:10
  • @BaummitAugen Thank you. Can you take a look at the updated question and possibly suggest a workaround? – Zizheng Tai May 03 '16 at 00:16
  • 1
    No problem. Please ask a new question in a new question so that we need not rewrite history and can focus on a single issue in the answers. – Baum mit Augen May 03 '16 at 00:19
  • @BaummitAugen Thanks! The new question is at http://stackoverflow.com/questions/36993646/avoid-returning-by-reference-argument. – Zizheng Tai May 03 '16 at 00:21
  • @BaummitAugen `foo.getOrElse(Foo()).bla();` would be fine. The reference does not dangle until the end of the full-expression, so I would not say that OP's code has any dangling references. There is only danger if the call is prefaced by `auto& ref = ` or similar. – M.M May 03 '16 at 04:53
  • @M.M Something like `int x = someInt.getOrElse(123)` would be find? – Zizheng Tai May 03 '16 at 05:26

1 Answers1

2

It's fine to return a reference as long as the object referred to is not destroyed before control leaves the function (i.e., an automatic local variable or parameter, or a temporary created inside the function).

In this case, you are potentially returning a reference to the temporary Foo() in the calling context, which is fine because that temporary is guaranteed to survive until the end of the full-expression containing the call. However, the reference would become dangling after the full-expression, i.e., the lifetime of the Foo() temporary is not extended, so care must be taken not to access it again after that point.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312