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()
在右值上使用时不能适当地延长所包含对象的生存期?
答案 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()
在右值上使用时不能正确延长所包含对象的生存期?
它不能延长寿命。没有这样的语言设施。选择是返回一个值(这将强制执行您可能不需要的移动,但将是安全的)或返回一个引用(此操作避免了不必要的移动,但依赖程序员安全地使用它)。图书馆选择了后者。