伊利德返回参数
Elide returned parameter
假设我们有一个函数:
Foo bar(Foo&& foo)
{
// assume `Foo` is move constructible
return std::move(foo);
}
在此示例中:
// (1)
Foo foo = bar(Foo{});
而这个:
// (2)
Foo foo;
// do something with `foo` so that compiler can't optimize it away
...
Foo foo2 = bar(std::move(foo));
我知道在(2)中,我们几乎肯定无法避免默认构造(foo
)和移动构造(返回值为bar
),但是编译器可以省略第三个移动构造(从bar
的返回值到foo2
)。
但是(1)呢?在语义上有两种移动结构(一种从临时参数到bar
的返回值,另一种从返回值到foo
),其中第二个几乎总是可以省略。但是第一个呢?在示例(1)中,是否有可能某些激进的优化只能使一个构造发生,因此它实际上与以下相同:
Foo foo;
这可能吗?
它可以,但在此意图之外使用并不完全安全,请小心使用它。
你可以使用右值来完全消除构造,但这意味着你的中间函数(即bar
)必须传递并接受引用参数。坚持使用右值引用并不难,因此可以这样的事情:
class A { /* ... */ };
A && bar (A && a) {return std::move(a);}
A a1 = A();
A a2 = bar( A() );
A a3 = bar( bar( A() ) );
经验法则:如果按值传递,则只能通过优化删除虚假的中间对象实例,因为编译器必须检查实例的使用情况并重新排列。但是,对于引用,我们直接声明我们需要一个已经可用的对象,并且右值将其扩展到临时对象。
像这样传递引用的"陷阱"是,如果您将引用传递给范围已过期的对象,那么您就遇到了麻烦。(例如,返回对局部变量的右值引用,并不比常规引用好,但这种情况可能会被编译器标记,而右值可能不会)。
A && bad_valid_return() {
A temp;
return std::move(temp);
}
A a4 = bad_valid_return(); // not ok, object is destroyed once we return!
A good_valid_return() {
A temp;
return std::move(temp);
// better but we can only remove the result's construction via optimize
}
对于它的价值,你也可以这样做:
A && a5 = good_valid_return();
a5
本质上是一个正则变量(它的类型将是A&
,使用时几乎与A a5
相同)。它将保存返回的实际临时,因此临时被构造到位。这甚至可以绕过私有对象成员 - 即使operator=
和构造函数是私有的(并且与good_valid_return
成为好友),赋值也会起作用a5
。
关于bar
在一般情况下,这几乎是绝对不允许的,以完全避免移动操作员。将每个"按值"值传递的值视为构造障碍 - 越过该点的值必须产生一个新容器,除非"明显"只需要一个对象。
这些"明显"的情况是返回值优化情况。作为单独的代码单元,函数无法知道如何使用其值,因此在"按值"传递中进行交易的函数必须假定需要一个新对象。
例外是内联 - 函数代码在引用它的地方进行了优化,基本上完全删除了函数调用 - 我希望这是您的 (1) 案例唯一一次优化远离任何额外的对象/移动/副本,而无需使用右值引用直接告诉编译器这就是你打算发生的事情。
看起来确实是(1)中可能发生的情况,但是例如,您至少需要使用GCC进行-O3
优化才能发生这种情况。(也许是O2,但我不会这么认为)
没记错的话,RVO 在这里不适用,原因有两个:
- 返回的类型(对 Foo 的 R 值引用)与函数的返回类型不同
- 返回的值不是局部变量或临时变量
但是,如果您的复制/移动构造函数没有任何副作用(不适用于 deepmax 的 Foo 类)并且 bar 足够简单,我很确定现代编译器能够内联 bar 并优化除默认构造函数之外的所有内容在 as-if 规则下。
- 使用作为参数返回的指针的最佳做法是什么
- 有没有办法根据 lambda 参数返回类型部分专用化我的模板化函数?
- 如何通过函数参数返回指向不规则数组的指针
- void 函数中的指针参数返回不一致的值
- 如何修复用于根据参数返回不同类型的模板类中的错误C2679?
- 是否可以通过引用通过参数返回参考
- 在C++中,如何根据类中的参数返回不同的泛型类型
- 如何根据枚举参数返回其他类型
- GoogleMock,按参数返回和正常返回,消耗数组
- 功能是否有可能使用其参数返回指针
- 推论成员函数参数 /返回类型
- C++ 基于模板参数返回类型的模板函数
- 参考参数返回副本
- 根据模板参数返回有价值的
- std::string 应该按函数的值返回还是按"std::string &s"作为参数返回?
- 将适当类型的迭代器作为参数返回适当类型的STL容器
- 根据参数返回类型
- 如何实现模板函数从模板参数返回向量
- 如何根据模板参数返回不同的类型
- 我可以从引用传递的参数返回值中声明const int吗