0

编译器优化后的程序速度哪个更好:按值返回,还是按引用返回持久对象?

/// 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 );
    }
};
4

0 回答 0