C++ 嵌套循环内部或外部变量声明的性能比较

C++ 嵌套循环内部或外部变量声明的性能比较,c++,C++,案例一 案例二 while (!channels_.empty()) { for (auto it = channels_.begin(); it != channels_.end(); ++it) { time_t stop_time; if (it->second->active_playlist()->st

案例一

案例二

while (!channels_.empty())
            {
                for (auto it = channels_.begin(); it != channels_.end(); ++it)
                {
                    time_t stop_time;
                    if (it->second->active_playlist()->status_stop_time(it->second->on_air_row(), stop_time))
                    {

                    }
                }
            }

在案例I和II中,变量stop_time在嵌套循环外部或内部声明。哪一个性能更好?为什么?

对于许多与绩效相关的问题,一般的答案是“测量它,自己看看”。如果容易的话,就做吧。在这种情况下,很容易


有时,查看汇编代码是件好事——如果两种情况下的代码是相同的(我猜是相同的),您甚至不需要测量它的性能。

标准对性能几乎没有什么规定,但有一条明确的规则,即优化不能改变可观察到的副作用

该标准没有描述堆栈或堆的使用情况,因此编译器在使用变量之前的任何时间为其分配空间都是完全合法的

但是,最佳选择取决于各种因素。在最常见的体系结构上,只需在两个位置(入口和出口)执行所有堆栈指针调整是最有意义的。在x86上,将堆栈指针更改640而不是在8上,没有成本差异

此外,如果编译器可以确保该值没有改变,那么优化器也可以将赋值从循环中提出来

实际上,x86和基于arm的平台上的主流编译器(gcc、clang、msvc)会将堆栈分配聚合为单个上下循环,并在给定足够的优化器设置/参数的情况下提升循环不变量

如果有疑问,检查组件或基准

我们可以通过以下方式快速演示这一点:


你为什么不计时看看呢?我怀疑你会注意到任何不同我打赌它们编译成完全相同的代码。案例二更快?因为变量不是只初始化一次。只是想要一些好的理论reasonings@seccpur变量根本没有初始化。“@anatolyg”:感谢“查看程序集”的评论,这是我没有考虑过的。使用计时器测量显然更好,但因为时间差将是无穷小的(以毫秒的几分之一为单位)在这里,有时我看到pc时钟的分辨率进来了。@seccput用定时器测量并不是“明显更好”。如果汇编代码相同,就没有什么可测量的了。
while (!channels_.empty())
        {
            time_t stop_time;
            for (auto it = channels_.begin(); it != channels_.end(); ++it)
            {

                if (it->second->active_playlist()->status_stop_time(it->second->on_air_row(), stop_time))
                {

                }
            }
        }
#include <vector>

struct Channel
{
  void test(int&);
};

std::vector<Channel> channels;

void test1()
{
  while (!channels.empty())
  {
    for (auto&& channel : channels)
    {
      int stop_time;
      channel.test(stop_time);
    }
  }
}

void test2()
{
  while (!channels.empty())
  {
    int stop_time;
    for (auto&& channel : channels)
    {
      channel.test(stop_time);
    }
  }
}

void test3()
{
  int stop_time;
  while (!channels.empty())
  {
    for (auto&& channel : channels)
    {
      channel.test(stop_time);
    }
  }
}
    test1():
            pushq   %rbp
            pushq   %rbx
            subq    $24, %rsp
    .L8:
            movq    channels+8(%rip), %rbp
            movq    channels(%rip), %rbx
            cmpq    %rbp, %rbx
            je      .L10
    .L7:
            leaq    12(%rsp), %rsi
            movq    %rbx, %rdi
            addq    $1, %rbx
            call    Channel::test(int&)
            cmpq    %rbx, %rbp
            jne     .L7
            jmp     .L8
    .L10:
            addq    $24, %rsp
            popq    %rbx
            popq    %rbp
            ret

    test2():
            pushq   %rbp
            pushq   %rbx
            subq    $24, %rsp
    .L22:
            movq    channels+8(%rip), %rbp
            movq    channels(%rip), %rbx
            cmpq    %rbp, %rbx
            je      .L20
    .L14:
            leaq    12(%rsp), %rsi
            movq    %rbx, %rdi
            addq    $1, %rbx
            call    Channel::test(int&)
            cmpq    %rbx, %rbp
            jne     .L14
            jmp     .L22
    .L20:
            addq    $24, %rsp
            popq    %rbx
            popq    %rbp
            ret

    test3():
            pushq   %rbp
            pushq   %rbx
            subq    $24, %rsp
    .L26:
            movq    channels+8(%rip), %rbp
            movq    channels(%rip), %rbx
            cmpq    %rbp, %rbx
            je      .L28
    .L25:
            leaq    12(%rsp), %rsi
            movq    %rbx, %rdi
            addq    $1, %rbx
            call    Channel::test(int&)
            cmpq    %rbx, %rbp
            jne     .L25
            jmp     .L26
    .L28:
            addq    $24, %rsp
            popq    %rbx
            popq    %rbp
            ret