为什么c ++ 17的emplace()函数没有经过ref限定?

时间:2019-01-09 19:13:28

标签: c++ language-lawyer c++17

C ++ 17为几个emplace_back()类型的函数(std::optional<>也有一个)引入了新的函数签名,但是它们没有ref限定。即使对象的生存期未延长,这也允许在临时目录上调用emplace_back()并将其绑定到左值引用。请考虑以下内容:

#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';
}

输出:

constructor called: 5
destructor called
a: 5
constructor called: 5
destructor called
v: 0
constructor called: 5
destructor called
a2: 5

我找不到与此相关的任何现有错误或问题,但也许我只是缺少了一些东西。对于std::optional<>::value(),它主要有效,但仍允许绑定到const左值引用,而不能适当地延长所包含类型的生存期。

是否有任何原因为什么这些函数不具有ref限定,以及为什么std::optional<>::value()在右值上使用时不能适当地延长所包含对象的生存期?

2 个答案:

答案 0 :(得分:1)

std库中几乎没有任何东西是经过ref限定的。

对于value,它返回右值引用。如果您有一个右值限定方法返回对内部状态的引用,则有两种选择。

您可以返回值,也可以返回右值引用。

如果返回值,则意味着右值可选的.value()会移动,而左值可选的.value()不会移动。这可能令人惊讶。

.value()返回右值的代价是不延长参考生存期。 .value()返回右值副本的成本是移动的成本,加上其行为有所不同的惊奇。

两者都有缺点。我记得这是可选设计的讨论重点。如果我的记忆是正确的,那意味着这个决定是睁开眼睛做出的。

除非对引用生存期扩展进行了极大的改进,否则将rvalues返回内部状态的rvalues上的函数始终将绑定到const&,而不会延长外部对象的生存期。

我的经历中真正的痛点是for(:)循环;

std::optional<std::vector<int>> try_get_vec();

for (int x : try_get_vec().value()) // I know the optional won't be empty

上面有悬挂的参考文献。

答案 1 :(得分:-1)

  

是否有任何原因导致这些函数不具有引用资格,并且[...]

标准库中有很多功能可以被&限定,但没有。在右值上调用类似emplace()的方法可能是一个很好的示例代码,可能没有任何意义。

另一方面,可能没有很多人试图在rvalues上调用类似emplace()的方法,所以也许&限定所有这些函数的回报是不值得的。

  

[...]以及为什么std::optional<>::value()在右值上使用时不能正确延长所包含对象的生存期?

它不能延长寿命。没有这样的语言设施。选择是返回一个值(这将强制执行您可能不需要的移动,但将是安全的)或返回一个引用(此操作避免了不必要的移动,但依赖程序员安全地使用它)。图书馆选择了后者。