C++中对象自身赋值运行异常?求值顺序与未定义行为相关问题
核心规则说明
- C++17确实明确了内置赋值运算符的求值顺序:右操作数的所有求值和副作用,都序列早于(sequenced before)左操作数的求值和最终的赋值操作。重载的赋值运算符作为函数调用,参数求值顺序仍然是未指定的,但你示例中std::string迭代器在gcc实现下为原生指针,用到的是内置赋值运算符,适用该规则。
第一个示例*beg = *beg++的行为解释
你的输出完全符合C++17的规则,执行顺序如下:
- 先计算右操作数
*beg++:后缀自增返回自增前的迭代器值,解引用得到字符'h',同时副作用触发beg自增,指向字符串的第二个字符'e' - 再计算左操作数
*beg:此时beg已经自增,指向第二个字符'e' - 执行赋值操作:把右操作数得到的
'h'赋值给左操作数指向的第二个字符
最终字符串变为"hhllo",beg指向第二个字符'h',和你得到的输出完全一致。
第二个示例*beg = (*beg)++的行为解释
为什么'h'没有变为'i'
执行顺序同样符合C++17规则:
- 先计算右操作数
(*beg)++:后缀自增返回自增前的字符值'h',同时副作用触发beg指向的第一个字符自增为'i' - 再计算左操作数
*beg:指向第一个字符(此时第一个字符已经临时变为'i') - 执行赋值操作:把右操作数返回的原始值
'h'赋值给第一个字符,直接覆盖了刚才自增得到的'i'
最终字符串第一个字符还是'h',和你得到的"hello"输出一致,beg没有被修改,仍然指向第一个字符'h'。
关于未定义行为的说明
C17之前,赋值运算符左右操作数的求值顺序没有明确规定,同一个表达式内对同一个对象多次修改会触发未定义行为,不同编译器可能得到不同结果。但C17之后你这两个示例用到内置赋值运算符的场景,行为是明确定义的,不属于未定义行为,你的运行结果完全符合标准规定,不符合你预期只是因为你此前对赋值运算符的求值顺序理解有误。
内容的提问来源于stack exchange,提问作者Itachi Uchiwa
相关产品推荐
相关产品推荐

