C++17 introduced a new function signature for a few emplace_back()
type functions (std::optional<>
has one too), but they are not ref-qualified. This allows emplace_back()
to be called on a temporary and bound to lvalue references, even though the lifetime of the object is not extended. Consider the following:
#include <vector>
#include <optional>
#include <iostream>
struct A {
A(int i) : i(i) { std::cout << "constructor called: " << i << '\n'; }
~A() { std::cout << "destructor called\n"; }
int i;
};
int main() {
auto & a = std::optional<A>().emplace(5);
std::cout << "a: " << a.i << '\n';
auto & v = std::vector<A>().emplace_back(5);
std::cout << "v: " << v.i << '\n';
// This fails to compile, because value() *is*
// ref-qualified so it cannot bind to an lvalue reference
//auto & a2 = std::optional<A>(std::in_place, 5).value();
auto const & a2 = std::optional<A>(std::in_place, 5).value();
std::cout << "a2: " << a2.i << '\n';
}
The output:
constructor called: 5
destructor called
a: 5
constructor called: 5
destructor called
v: 0
constructor called: 5
destructor called
a2: 5
I couldn't find any existing bugs or questions related to this, but maybe I'm just missing something. In the case of std::optional<>::value()
, it mostly works, but still allows binding to const lvalue references whilst not properly extending the contained type's lifetime.
Is there any reason why these functions are not ref-qualified, and why std::optional<>::value()
doesn't properly extend the lifetime of the contained object when used on an rvalue?