gpt4 book ai didi

c++ - 是否允许 C++ 编译器在评估其参数之前将函数 ptr 存储在寄存器中?

转载 作者:太空狗 更新时间:2023-10-29 21:09:57 26 4
gpt4 key购买 nike

我和我的同事正在与我们开发的应用程序中的一个相当奇怪的错误作斗争。最终我们修复了它,但我们仍然不确定编译器所做的是否合法。

假设我们有这样的代码:

class B {
public:
virtual int foo(int d) { return d - 10; }
};

class C : public B {
public:
virtual int foo(int d) { return d - 11; }
};

class A {
public:
A() : count(0) { member = new B;}
int bar() {
return member->foo(renew());
}

int renew() {
count++;
delete member;
member = new C;
return count;
}
private:
B *member;
int count;
};

int square() {
A a;
cout << a.bar() << endl;
return 0;
}

对于函数A::bar,Visual Studio x86 编译器在使用/O1 编译时会生成类似这样的内容(您可以在godbolt 上查看完整代码| ):

        push    esi
push edi
mov edi, ecx
mov eax, DWORD PTR [edi] ; eax = member
mov esi, DWORD PTR [eax] ; esi = B::vtbl
call int A::renew(void) ; Changes the member, vtable and esi are no longer valid
mov ecx, DWORD PTR [edi]
push eax
call DWORD PTR [esi] ; Calls wrong stuff (B::vtbl[0])
pop edi
pop esi
ret 0

这种优化是标准允许的还是未定义的行为?我无法使用 GCC 或 clang 获得类似的程序集。

最佳答案

为了清楚起见,这里是 Order of evaluation文档 Jarod42 已经链接,相关引用:

14) In a function-call expression, the expression that names the function is sequenced before every argument expression and every default argument.

所以我们应该阅读声明

return member->foo(renew());

作为

return function-call-expression;

函数调用表达式在哪里

{function-naming-expression member->foo} ( {argument-expression renew()} )

因此,function-naming-expression member->foo sequenced-before 参数表达式。已经链接的文档说

If A is sequenced before B, then evaluation of A will be complete before evaluation of B begins.

所以我们必须首先完全评估member->foo。我认为它应该像这样扩展

// 1. evaluate function-naming-expression
auto tmp_this_member = this->member;
int (B::*tmp_foo)(int) = tmp_this_member->foo;

// 2. evaluate argument expression
int tmp_argument = this->renew();

// 3. make the function call
(tmp_this_member->*tmp_foo) ( tmp_argument );

... 这正是您所看到的。这是 C++17 要求的排序,在此之前排序和行为都是未定义的。


tl;dr 编译器是正确的,即使它能运行,该代码也很糟糕。

关于c++ - 是否允许 C++ 编译器在评估其参数之前将函数 ptr 存储在寄存器中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56456952/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com