我想知道为什么C++在返回T时不对std::optional<T>执行RVO。也就是说,
struct Bar {};
std::optional<Bar> get_bar()
{
return Bar{}; // move ctor of Bar called here
// instead of performing RVO
}
Bar get_bar2()
{
return Bar{}; // NO move ctor called
// RVO performed
}
std::optional<Bar> get_bar_rvo()
{
std::optional<Bar> opt;
opt.emplace();
return opt; // NO move ctor called
// ROV performed
}在上述情况下,get_bar2执行RVO,而get_bar不执行RVO。
使用更多的提示,编译器能够优化get_bar_rvo,但是代码会变得更长、更烦人。
在参考文献中,我了解到get_bar不符合“强制复制/移动操作”的要求。
在对象的初始化中,当初始化器表达式是与变量类型相同的类类型(忽略cv限定)的prvalue时:
因为std::optional<T>和T不是相同的类类型,所以RVO不是强制性的。
但是,我认为对std::optional<T>执行RVO应该非常容易,而且非常有用,不需要手动将较长的代码编写为get_bar_rvo。
为什么我的编译不能像get_bar一样识别和优化get_bar2
环境: MacOS
Apple clang version 13.1.6 (clang-1316.0.21.2.5)
Target: arm64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin用-std=c++17 -O3编译
发布于 2022-11-16 11:56:31
get_bar_rvo不执行RVO,它执行NRVO (称为返回值优化)。这不能保证。
对于get_bar,与其自己构建Bar,不如使用std::make_optional或它的就地构造函数(6)将其留给std::optional
std::optional<Bar> get_bar()
{
return std::make_optional<Bar>();
// or return std::optional<Bar>(std::in_place);
}这将像预期的那样执行RVO。
发布于 2022-11-16 12:22:11
get_bar()返回std::optional<Bar>,并且不会像预期的那样复制或移动std::optional<Bar>。
Bar被移动到std::optional<Bar>,因为您创建了一个临时Bar,然后请求从它构建std::optional<Bar>。与RVO或NRVO无关。它是关于将对象传递给函数的。
我们不期望在像foo(Bar{})这样的旧函数调用中消除移动,std::optional构造函数也不例外。
https://stackoverflow.com/questions/74459462
复制相似问题