在循环中用作"const&"函数参数的临时对象的编译器优化?

Gar*_*and 3 c++ optimization visual-c++ c++11

我有一个永远的线程循环调用std::this_thread::sleep_for延迟10毫秒.持续时间是临时对象std::chrono::milliseconds(10).一些示例代码后,延迟调用似乎是"正常"和"典型".然而,仔细观察,很明显,在每个循环中,临时持续时间对象被创建并销毁一次.

// Loop A.
for (;;)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    // Do something.
}
Run Code Online (Sandbox Code Playgroud)

现在,如果在循环外创建持续时间对象(作为常量对象),则它将仅针对所有循环构造一次.请参阅下面的代码.

// Loop B.
const auto t = std::chrono::milliseconds(10);
for (;;)
{
    std::this_thread::sleep_for(t);
    // Do something.
}
Run Code Online (Sandbox Code Playgroud)

问题:由于std :: this_thread :: sleep_for使用"const&"作为其参数类型,所以任何C++编译器都会将Loop A中的临时持续时间对象优化为Loop B吗?

我在下面尝试了一个简单的测试程序 结果表明VC++ 2013没有优化"const&"临时对象.

#include <iostream>
#include <thread>

using namespace std;

class A {
public:
    A() { cout << "Ctor.\n"; }
    void ReadOnly() const {}  // Read-only method.
};

static void Foo(const A & a)
{
    a.ReadOnly();
}

int main()
{
    cout << "Temp object:\n";
    for (int i = 0; i < 3; ++i)
    {
        Foo(A());
    }

    cout << "Optimized:\n";
    const auto ca = A();
    for (int i = 0; i < 3; ++i)
    {
        Foo(ca);
    }
}
/* VC2013 Output:
Temp object:
Ctor.
Ctor.
Ctor.
Optimized:
Ctor.
*/
Run Code Online (Sandbox Code Playgroud)

Chr*_*phe 12

MSVC和其他现代编译器完全能够优化循环中的临时对象.

您的示例中的问题是您在构造函数中有副作用.根据C++标准,编译器不允许优化临时对象的创建/销毁,因为它不再产生相同的可观察效果(即打印3次).

如果你不再cout是某种东西,那么情况就完全不同了.当然,您必须查看为验证优化而生成的汇编代码.

例:

class A {
public:
    static int k;    
    A() { k++;  }   
    void ReadOnly() const {}  // Read-only method.
};
int A::k = 0; 

// Foo unchanged

int main()
{
    for(int i = 0; i < 3; ++i)
        Foo(A());  // k++ is a side effect, but not yet observable 
    volatile int x = A::k;     // volatile can't be optimized away

    const auto ca = A();
    for(int i = 0; i < 3; ++i)
        Foo(ca);
    x = A::k;     // volatile can't be optimized away
    cout << x << endl; 
}
Run Code Online (Sandbox Code Playgroud)

优化器完全注意到它是相同的静态变量,它会增加,而不是在其他地方使用.所以这里生成的汇编程序代码(提取):

mov eax, DWORD PTR ?k@A@@2HA        ; A::k     <=== load K 
add eax, 3                                     <=== add 3 to it (NO LOOP !!!)
mov DWORD PTR ?k@A@@2HA, eax        ; A::k     <=== store k
mov DWORD PTR _x$[ebp], eax                    <=== store a copy in x 
inc eax                                        <=== increment k
                                               <=== (no loop since function doesn't perform anything)
mov DWORD PTR ?k@A@@2HA, eax        ; A::k     <=== store it 
mov DWORD PTR _x$[ebp], eax                    <=== copy it to x
Run Code Online (Sandbox Code Playgroud)

当然,您需要在发布模式下进行编译.

如您所见,编译器非常聪明.因此,让他完成自己的工作,专注于您的代码设计,并牢记: 过早优化是所有邪恶的根源 ;-)