Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编译器会将这个表达式优化为一个临时常量,而不是每次迭代都解析它吗?_C++_Loops_Optimization_Expression - Fatal编程技术网

C++ 编译器会将这个表达式优化为一个临时常量,而不是每次迭代都解析它吗?

C++ 编译器会将这个表达式优化为一个临时常量,而不是每次迭代都解析它吗?,c++,loops,optimization,expression,C++,Loops,Optimization,Expression,我有以下循环: for (unique_ptr<Surface>& child : Children) { child->Gather(hit); if (hit && HitTestMode == HitTestMode::Content && child->MouseOver && !mouseOver) { mouseOver = true; } } 转换为一

我有以下循环:

for (unique_ptr<Surface>& child : Children)
{
    child->Gather(hit);

    if (hit && HitTestMode == HitTestMode::Content && child->MouseOver && !mouseOver)
    {
        mouseOver = true;
    }
}
转换为一个临时常量,并使用它,而不是在每次迭代中解析表达式,类似于我这样做:

bool contentMode = hit && HitTestMode == HitTestMode::Content;

for (unique_ptr<Surface>& child : Children)
{
    child->Gather(hit);

    if (contentMode && child->MouseOver && !mouseOver)
    {
        mouseOver = true;
    }
}
bool contentMode=hit&&HitTestMode==HitTestMode::Content;
用于(唯一的儿童:儿童)
{
孩子->收集(命中);
if(contentMode&&child->MouseOver&&MouseOver)
{
mouseOver=true;
}
}
奖金问题:


正在检查
!mouseOver
值得(为了跳过条件
mouseOver=true;
如果已经设置)?或者,不管怎样,简单地重新设置它会更快吗?

这个优化是否会发生的答案取决于
命中的对象是什么,
命中的模式是什么,
命中的模式是什么,
命中的模式是什么?
命中的模式::内容是什么?
以及是否可能通过调用
子对象->聚集()来改变它们

如果这些标识符是编译器可以证明没有修改的常量或局部变量,那么子表达式
hit&&HitTestMode==HitTestMode::Content
完全有可能被提升

例如,考虑以下示例的可编译版本:

#include <memory>
#include <vector>

using namespace std;

class Surface
{
public:
    void Gather(bool hit);
    bool MouseOver;
};

enum class HitTestMode
{
    Content = 1,
    Foo = 3,
    Bar = 4,
};


extern HitTestMode hittestmode;

bool anyMiceOver( vector<unique_ptr<Surface> > & Children, bool hit)
{
    bool mouseOver = false;

    for (unique_ptr<Surface>& child : Children)
    {
        child->Gather(hit);

        if (hit && hittestmode == HitTestMode::Content && child->MouseOver && !mouseOver)
        {
            mouseOver = true;
        }
    }

    return mouseOver;
}
您将注意到,
hit
的检查已从循环中提升出来,如果它是
false
,则运行除了调用
child->Gather()
之外什么都不做的a循环

如果将
hitmodetest
更改为一个作为函数参数传递的变量,因此它不再可能被调用
子聚集(hit)
更改,然后,编译器还将提升对
hittestmode
值的检查,使其脱离循环,跳转到只调用
child->Gather()
的循环

使用本地
hittestmode
时,使用
-O2
将在循环之前计算
hit&&hittestmode==hittestmode::Content
,并将结果存储在寄存器中,但它仍将在每个循环迭代中测试寄存器,而不是优化到一个单独的循环,而该循环甚至不需要进行测试


由于您特别询问了VS2013编译器(使用
/Ox
/Ot
选项),它似乎没有将任何检查(对于
命中
命中测试模式
)从循环中移除-它似乎只需将这些变量的值保留在寄存器中

可能不会。查看生成的汇编代码(使用
g++-O-fverbose asm-S
)。关于性能,基准!(我认为不管怎样,只需再次设置鼠标上方的
会更快)回答奖金问题:再次设置会更快。分配完任务后,我会添加一个break语句,因为这样您就不必对其他孩子进行检查了。@programmerjake谢谢。不过,我不能打断,因为不管怎样,都需要对每个孩子执行一个操作(我从我的原始示例中漏掉了这个-我现在将更新它以包括这个)。下面是一个有趣的帖子,讨论为什么if语句会很昂贵:@d7samurai“奖金问题”到底是什么?你能详细说明一下吗?你应该每个问题问一个问题,你不能给任何回答的人任何奖金。请停下来。你可以问另一个(相关的)问题。此外,为了更好的实践,你不应该关心微观优化的这些事情,除非你会注意到任何真正的问题。就让它过去吧,让它变得更有成效。出于我们在这里的实际目的,您的可编译示例完全封装了实际实现的结构方式,因此您的分析是正确的。由于我知道一些编译器不知道的东西(即
HitTestMode
没有被
child->Gather()
触及),我可以随意折叠并将它们移出循环。但是,您的回答让我意识到,我可能希望
child->Gather()
能够在迭代过程中[hackly]更改
HitTestMode
,因此将表达式保留为“unheisted”。。但令人失望的是,VS没有在这里提升任何东西。
#include <memory>
#include <vector>

using namespace std;

class Surface
{
public:
    void Gather(bool hit);
    bool MouseOver;
};

enum class HitTestMode
{
    Content = 1,
    Foo = 3,
    Bar = 4,
};


extern HitTestMode hittestmode;

bool anyMiceOver( vector<unique_ptr<Surface> > & Children, bool hit)
{
    bool mouseOver = false;

    for (unique_ptr<Surface>& child : Children)
    {
        child->Gather(hit);

        if (hit && hittestmode == HitTestMode::Content && child->MouseOver && !mouseOver)
        {
            mouseOver = true;
        }
    }

    return mouseOver;
}
    mov rbx, QWORD PTR [rcx]      ; Children.begin()
    mov rsi, QWORD PTR 8[rcx]     ; Children.end()
    cmp rbx, rsi                 
    je  .L8                       ; early exit if Children is empty

    test    dl, dl                ; hit == 0?
    movzx   edi, dl
    je  .L5                       ; then goto loop L5

    xor ebp, ebp
    mov r12d, 1
    jmp .L7
    .p2align 4,,10
.L6:
    add rbx, 8
    cmp rsi, rbx                  ; check for end of Children
    je  .L2
.L7:
    mov rcx, QWORD PTR [rbx]
    mov edx, edi
    call    _ZN7Surface6GatherEb  ; call child->Gather(hit)
    cmp DWORD PTR hittestmode[rip], 1  ; check hittestmode
    jne .L6
    mov rax, QWORD PTR [rbx]      ; check child->MouseOver
    cmp BYTE PTR [rax], 0
    cmovne  ebp, r12d             ; set mouseOver appropriately
    jmp .L6
    .p2align 4,,10

.L5:                             ; loop L5 is run only when hit == 0
    mov rcx, QWORD PTR [rbx]     ; get net element in Children
    mov edx, edi
    add rbx, 8
    call    _ZN7Surface6GatherEb ; call child->Gather(hit)
    cmp rsi, rbx
    jne .L5

.L8:
    xor ebp, ebp
.L2:
    mov eax, ebp
    add rsp, 32
    pop rbx
    pop rsi
    pop rdi
    pop rbp
    pop r12
    ret