编译器优化后的程序速度哪个更好:按值返回,还是按引用返回持久对象?
/// Generate a 'foo' value directly as a return type.
template< typename T >
inline T gen_foo();
/// Get a 'foo' reference of a persistent object.
template< typename T >
inline T const& get_foo();
T
将是原语、指针、成员指针或用户定义的小型 PO、D. 类数据。
据我所知,它是按值传递,但也有可能是按引用传递的情况:
传值:
- 返回一个
T
是一个较小的对象,并且可以快速复制到调用者的变量中。 - 优化器可以使用 (N)RVO 和复制省略来删除返回的副本。
- 优化器可以将生成代码或生成的值内联到调用者的代码中。
- 程序不需要访问 RAM,无论是否缓存。
- 返回一个
参考传递:
- 优化器可能会完全评估持久值,并将其使用替换为文字等价物。这是否发生会影响分析的其余部分。
- 如果持久值被完全评估并替换为文字:
- 没有价值返回。
- 优化器可以轻松地内联文字。
- 程序不需要访问 RAM,无论是否缓存。
- 如果无法完全评估和替换持久值:
- 返回一个引用是一个小对象,并且可以快速复制到调用者的变量。
- 优化器可以使用 (N)RVO 和复制省略来避免返回副本。
- 优化器不能将生成代码或生成的值内联到调用者的代码中。
- 程序需要访问 RAM,尽管这可能在 L1/L2/等中。缓存。
背景:
我被迫考虑这一点,因为在某些平台上,如果我按值返回会触发一些浮点异常,但如果我按参数引用填充则不会。(这是给定的;这个问题不是要争论这一点。)所以,我想要的 API 和我被迫考虑使用的 API 是:
/// Generate a 'foo' value directly as a return type.
template< typename T >
inline T gen_foo();
/// Fill in a 'foo' passed in by reference.
template< typename T >
inline void fill_foo( T& r_foo );
因为,我讨厌“填充”API,(因为它将定义与初始化分开,防止创建临时对象等)我可以将其转换为按引用返回的版本,例如:
/// Forward-declare 'Initialized_Foo'.
template< typename T > struct Initialized_Foo;
/// Get a 'foo' reference; this returns a persistent reference to a static object.
template< typename T >
inline T const& get_foo()
{
#if 0
// BAD: This calls 'fill_foo' *every* time, and breaks const-correctness.
thread_local static const T foo;
fill_foo( const_cast< T& >( foo ) );
return foo;
#else
// GOOD: This calls 'fill_foo' only *once*, and honours const-correctness.
thread_local static const Initialized_Foo< T > initialized_foo;
return initialized_foo.data;
#endif
}
/// A 'foo' initializer to call 'fill_foo' at construction time.
template< typename T >
struct Initialized_Foo
{
T data;
Initialized_Foo()
{
fill_foo( data );
}
};