2010-03-29 91 views
3

鉴于后增量运算符的评估按什么顺序发生?

std::vector<CMyClass> objects; 
CMyClass list[MAX_OBJECT_COUNT]; 

是否明智做到这一点?

for(unsigned int i = 0; i < objects.size(); list[i] = objects.at(i++)); 

或者我应该扩大我的循环?

for(unsigned int i = 0; i < objects.size(); i++) 
{ 
    list[i] = objects.at(i); 
} 
+0

哪些类型做'list'和'objects'有哪些? – MSalters 2010-03-29 15:33:28

+0

我更新了我的问题以反映这一点。 – sum1stolemyname 2010-03-30 05:29:04

回答

11

前者是未定义的行为。在函数调用objects.at之前或之后,没有指定是否对list[i]进行评估(以便为作业的lhs提供左值)。

因此,表达式的各个部分都有一个合法的排序,其中i被访问(在list[i]中)并且被单独修改(在i++中),没有插入序列点。

这恰恰是C++标准中未定义行为的条件 - 是否存在这样的合法排序。 IIRC C标准表示略有不同,但具有相同的效果。

如果有疑问,不要写一个使用增量运算符的表达式,并且在表达式的任何其他位置使用相同的值。你可以用逗号运算符(i++, i++罚款)和条件运算符(i ? i++ : i--罚款)来完成它,因为它们中有序列点,但它很少值得。 ||&&,而类似p != end_p && *(p++) = something;的东西并不完全不合情理。任何其他用途,如果你盯着它足够长的时间,你通常可以制定一个评估顺序来排除干扰。

这不包括复杂的for表达式和for带有空体的循环的可理解性。

+1

&&和||也是序列点(假设没有超载) – 2010-03-29 14:43:02

+0

现在,在前面提到的for循环中使用它们会使它非常有趣。 – 2010-03-29 14:50:58

+0

-1。 Un **定义**行为?不确定,当然。在您正确解释时有两种可能的顺序,并且该标准不需要实现来记录在什么时候使用哪一个。但是这个标准并没有把每一个细节都定义为“未定义的行为”。这是一个更糟糕的情况,其中包括彻底崩溃和恶魔。 – MSalters 2010-03-29 14:54:42

6

有疑问时,更喜欢哪更容易理解(展开环)的形式。

(我认为list[i] = objects.at(i++)导致不确定的行为。)

+0

它确实。我试过了。 – sum1stolemyname 2010-03-29 14:27:11

1

参考ii++的表达式可能是未定义的行为。但是,因为它看起来像你使用的容器,可能你也许正如有人已经说过,递增后在使用它的产量不确定的行为同样表达一个变量写...

list = objects;        // if they're the same type 
list.assign(objects.begin(), objects.end()); // if not 
+1

或者在最坏的情况下使用std :: copy,如果这两个选项都不可用(比如list是一个C数组?)。 – 2010-03-29 15:12:55

1

。 但是,如果你想保持紧凑的形式,你可以引入一个序列点,去

for(unsigned int i = 0; i < objects.size(); list[i] = objects.at(i), i++); 
+0

这看起来像旧的“每个程序都可以编码为循环体”。 – Gorpik 2010-03-29 14:44:35

+0

不是吗?我记得这个表格经常在IOCCC中使用...... – 2010-03-29 14:49:52