首先评估赋值运算符的哪一侧?

问题描述 投票:0回答:5
int& foo() {
   printf("Foo\n");
   static int a;
   return a;
}

int bar() {
   printf("Bar\n");
   return 1;
}

void main() {
   foo() = bar();
}

我不确定应该先评估哪一个。

我在VC中尝试过先执行bar函数。然而,在 g++ (FreeBSD) 编译器中,它首先给出 foo 函数求值。

从上面的问题衍生出很多有趣的问题,假设我有一个动态数组(std::vector)

std::vector<int> vec;

int foobar() {
   vec.resize( vec.size() + 1 );
   return vec.size();
}

void main() {
   vec.resize( 2 );
   vec[0] = foobar();
}

根据之前的结果,vc 计算 foobar(),然后执行向量运算符[]。在这种情况下没有问题。但是,对于 gcc,由于正在评估 vec[0],并且 foobar() 函数可能会导致更改数组的内部指针。执行 foobar() 后,vec[0] 会失效。

这是否意味着我们需要将代码分开

void main() {
   vec.resize( 2 );
   int a = foobar();
   vec[0] = a;
}
c++ function evaluation assignment-operator order-of-execution
5个回答
9
投票

在这种情况下,评估顺序将是未指定的。不要写这样的代码

类似示例这里


7
投票

C++ 中控制是否定义求值顺序的概念称为 序列点

基本上,在一个序列点,可以保证该点之前的所有表达式(具有可观察到的副作用)都已被评估,并且尚未评估该点之后的任何表达式。

虽然有些人可能会感到惊讶,但赋值运算符并不是序列点。所有序列点的完整列表位于维基百科文章


2
投票

c++17 保证

bar()
将在
foo()
之前执行。

在 c++17 之前,这是未指定的行为,不同的编译器会按不同的顺序进行计算。如果表达式的两边都修改相同的内存位置,则行为未定义。


0
投票

表达式的求值顺序是 未指定的行为
这取决于编译器选择评估的顺序。

你应该避免编写这样的代码。
不过,如果没有副作用,那么顺序应该不重要。

如果顺序很重要,那么您的代码是错误/不可移植/可能会在不同的编译器上给出不同的结果**。


-1
投票

此代码有效吗?我知道 std::move 不会更改其参数的内容,但编译器可能会生成一段代码,在执行 -> 运算符之前将 unique_ptr 的内容移动到某处?

void CResourceBundle::addTexture(std::unique_ptr<CTexture> puTexture)
{
    FAULT_IF(!puTexture, "Invalid argument");

    m_Textures[puTexture->getName()] = std::move(puTexture);
}
© www.soinside.com 2019 - 2024. All rights reserved.