这是绑定到要突变的非 RVO return 值的惯用方式吗?
Is this the idiomatic way to bind to a non-RVO return value to be mutated?
让我们假设一个无法更改的示例函数(例如,因为它在没有手头源代码的情况下链接),并且不受 NRVO 的约束。类似于以下内容:
auto f()
{
std::vector<int> v1 { 3, 2, 1 };
std::vector<int> v2 { 2, 1, 3 };
/* RVO impossible. */
return someRuntimeCondition ? v1 : v2;
}
来电方
auto&& vec = f(); /* Extend lifetime to current scope. */
std::sort(vec.begin(), vec.end()); /* Const-lvalue ref. was no option. */
这应该避免从 return 值移动构建局部 std::vector
。但我不经常看到这样的片段。我对上述片段的推理是错误的,还是像 f()
这样的函数非常罕见以至于依赖 RVO 是更惯用的方法?
我想了解如何在 RVO 不适用的假设下绑定 f()
的 return 值。
我不知道有什么惯用的方法来处理这个问题,但你总是可以这样做:
auto f()
{
std::vector<int> v1 { 3, 2, 1 };
std::vector<int> rv { 2, 1, 3 }; // return value
if(someRuntimeCondition)
std::swap(v1, rv);
return rv;
}
所以你总是确保你只 return 一个对象;
我想到了另一种方法,就像这样:
auto f()
{
std::vector<int> v1 { 3, 2, 1 };
std::vector<int> v2 { 2, 1, 3 };
return std::vector<int>{std::move(someRuntimeCondition ? v1 : v2)};
}
这应该调用 C++17
的 guaranteed RVO,在运行时将任何向量移动到调用者的堆栈上。
自 C++17 起,如果一个函数 returns 按值那么下面两个选项完全相同:
auto a = f();
auto&& a = f();
除了decltype(a)
的结果。 result对象在两种情况下都是由a
命名的,result对象是直接在函数中用return
语句初始化的
在 C++17 之前,结果对象始终是一个临时对象,并且 auto a = f();
从临时对象复制初始化 a
,此操作可选地可省略。
有些人确实使用 auto&& a = f();
的做法来抵御未实现可选复制省略的编译器。这有利也有弊。
我个人使用前者,因为我使用的是 C++17 ,甚至在此之前,我只使用进行最大复制省略的编译器。我实际上并不知道有任何编译器没有在这里进行复制省略,除了旧版本的 MSVC 运行 在调试模式下。
但我可以想象,为使用旧编译器的客户编写代码库的人可能会出于性能原因而觉得有必要修改他们的代码。
让我们假设一个无法更改的示例函数(例如,因为它在没有手头源代码的情况下链接),并且不受 NRVO 的约束。类似于以下内容:
auto f()
{
std::vector<int> v1 { 3, 2, 1 };
std::vector<int> v2 { 2, 1, 3 };
/* RVO impossible. */
return someRuntimeCondition ? v1 : v2;
}
来电方
auto&& vec = f(); /* Extend lifetime to current scope. */
std::sort(vec.begin(), vec.end()); /* Const-lvalue ref. was no option. */
这应该避免从 return 值移动构建局部 std::vector
。但我不经常看到这样的片段。我对上述片段的推理是错误的,还是像 f()
这样的函数非常罕见以至于依赖 RVO 是更惯用的方法?
我想了解如何在 RVO 不适用的假设下绑定 f()
的 return 值。
我不知道有什么惯用的方法来处理这个问题,但你总是可以这样做:
auto f()
{
std::vector<int> v1 { 3, 2, 1 };
std::vector<int> rv { 2, 1, 3 }; // return value
if(someRuntimeCondition)
std::swap(v1, rv);
return rv;
}
所以你总是确保你只 return 一个对象;
我想到了另一种方法,就像这样:
auto f()
{
std::vector<int> v1 { 3, 2, 1 };
std::vector<int> v2 { 2, 1, 3 };
return std::vector<int>{std::move(someRuntimeCondition ? v1 : v2)};
}
这应该调用 C++17
的 guaranteed RVO,在运行时将任何向量移动到调用者的堆栈上。
自 C++17 起,如果一个函数 returns 按值那么下面两个选项完全相同:
auto a = f();
auto&& a = f();
除了decltype(a)
的结果。 result对象在两种情况下都是由a
命名的,result对象是直接在函数中用return
语句初始化的
在 C++17 之前,结果对象始终是一个临时对象,并且 auto a = f();
从临时对象复制初始化 a
,此操作可选地可省略。
有些人确实使用 auto&& a = f();
的做法来抵御未实现可选复制省略的编译器。这有利也有弊。
我个人使用前者,因为我使用的是 C++17 ,甚至在此之前,我只使用进行最大复制省略的编译器。我实际上并不知道有任何编译器没有在这里进行复制省略,除了旧版本的 MSVC 运行 在调试模式下。
但我可以想象,为使用旧编译器的客户编写代码库的人可能会出于性能原因而觉得有必要修改他们的代码。