为什么我分配一个对象本身不能正常工作?
Why my assigning an object itself doesn't work properly?
据我所知,对于不保证其操作数求值顺序的运算符,我们不应多次修改操作数。
这里有我写的这个片段:
- 我正在使用符合 C++20 标准的 gcc 编译它:
-std=c++2b
.
int main(){
std::string s = "hello";
auto beg = s.begin();
*beg = *beg++;
std::cout << s << " " << *beg << std::endl;
}
为什么我会得到这个输出?
hhllo h
这个:
*beg = (*beg)++;
std::cout << s << " " << *beg << '\n';
产生此输出:
hello h
为什么值 'h'
没有增加到 'i'
?
这里发生了什么?通常,这会将 s
中的第一个字符分配回自身,然后递增 beg
迭代器。但是迭代器并没有自增,而是值变了!我敢打赌这是因为 未定义的行为 ,但如果是这样,那么有人可以向我解释一下吗?
C++17标准有没有在'sequenced'运算符中加入赋值运算符?如果是这样,为什么它在我的示例中不能正常工作?
所有这些结果都是正确的。你的误解来自于不知道后缀增量是如何工作的。
*beg = *beg++;
根据 C++ 运算符优先级规则,后缀运算符首先出现。所以这是 *beg = *(beg++)
.
C++17 强制赋值运算符在计算左侧之前完全计算右侧的所有表达式,包括所有副作用。
后缀迭代器递增左值,但它returns 原始值 的副本。原始值是指向第一个字符的迭代器。所以在评估 beg++
之后,beg
将改变其位置(因此指向第二个字符)。但是表达式的值是指向第一个的迭代器。
然后取消引用此迭代器,从而返回对第一个字符的引用。
之后,评估lhs。 beg
如前所述,指向第二个字符。所以 *beg
是对第二个字符的引用,它被分配给第一个字符的值。
*beg = (*beg)++;
所以这是反过来的。 *beg
是对第一个字符的引用,然后后缀递增。这意味着 *beg
引用的对象被递增,但是表达式 的 值是 原始值 的副本。即,增加前的字符:'h'
.
然后您将此字符分配给第一个字符,从而覆盖您刚刚递增的内容。
顺便说一句:如果您必须深入了解这个细节才能弄清楚表达式的作用,那么您不应该那样写表达式。避免使用后缀表达式,除非它们在某些方面是绝对必要的。
据我所知,对于不保证其操作数求值顺序的运算符,我们不应多次修改操作数。
这里有我写的这个片段:
- 我正在使用符合 C++20 标准的 gcc 编译它:
-std=c++2b
.
int main(){
std::string s = "hello";
auto beg = s.begin();
*beg = *beg++;
std::cout << s << " " << *beg << std::endl;
}
为什么我会得到这个输出?
hhllo h
这个:
*beg = (*beg)++;
std::cout << s << " " << *beg << '\n';
产生此输出:
hello h
为什么值
'h'
没有增加到'i'
?这里发生了什么?通常,这会将
s
中的第一个字符分配回自身,然后递增beg
迭代器。但是迭代器并没有自增,而是值变了!我敢打赌这是因为 未定义的行为 ,但如果是这样,那么有人可以向我解释一下吗?C++17标准有没有在'sequenced'运算符中加入赋值运算符?如果是这样,为什么它在我的示例中不能正常工作?
所有这些结果都是正确的。你的误解来自于不知道后缀增量是如何工作的。
*beg = *beg++;
根据 C++ 运算符优先级规则,后缀运算符首先出现。所以这是 *beg = *(beg++)
.
C++17 强制赋值运算符在计算左侧之前完全计算右侧的所有表达式,包括所有副作用。
后缀迭代器递增左值,但它returns 原始值 的副本。原始值是指向第一个字符的迭代器。所以在评估 beg++
之后,beg
将改变其位置(因此指向第二个字符)。但是表达式的值是指向第一个的迭代器。
然后取消引用此迭代器,从而返回对第一个字符的引用。
之后,评估lhs。 beg
如前所述,指向第二个字符。所以 *beg
是对第二个字符的引用,它被分配给第一个字符的值。
*beg = (*beg)++;
所以这是反过来的。 *beg
是对第一个字符的引用,然后后缀递增。这意味着 *beg
引用的对象被递增,但是表达式 的 值是 原始值 的副本。即,增加前的字符:'h'
.
然后您将此字符分配给第一个字符,从而覆盖您刚刚递增的内容。
顺便说一句:如果您必须深入了解这个细节才能弄清楚表达式的作用,那么您不应该那样写表达式。避免使用后缀表达式,除非它们在某些方面是绝对必要的。