Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 那么为什么i=++;i+;1在C+中定义良好+;11?_C++_C++11_Undefined Behavior_Language Lawyer - Fatal编程技术网

C++ 那么为什么i=++;i+;1在C+中定义良好+;11?

C++ 那么为什么i=++;i+;1在C+中定义良好+;11?,c++,c++11,undefined-behavior,language-lawyer,C++,C++11,Undefined Behavior,Language Lawyer,我见过类似的情况,也读过有关它的文章。但我还是不明白。为什么i=i+++1在C++11中定义得很好,而i=i+++1没有定义?该标准是如何定义的 通过我的计算,我得到了以下“排序前”图(其中箭头表示“排序前”关系,所有内容都是值计算,除非另有规定): 我用黑星标记了I的副作用,用白星标记了I的值计算。根据我的逻辑,它们之间似乎没有顺序。标准上说: 如果标量对象上的副作用相对于同一标量对象上的另一副作用或使用同一标量对象的值进行的值计算未排序,则该行为未定义 书中的解释没有帮助我理解。左值到右值的

我见过类似的情况,也读过有关它的文章。但我还是不明白。为什么
i=i+++1
在C++11中定义得很好,而
i=i+++1
没有定义?该标准是如何定义的

通过我的计算,我得到了以下“排序前”图(其中箭头表示“排序前”关系,所有内容都是值计算,除非另有规定):

我用黑星标记了
I
的副作用,用白星标记了
I
的值计算。根据我的逻辑,它们之间似乎没有顺序。标准上说:

如果标量对象上的副作用相对于同一标量对象上的另一副作用或使用同一标量对象的值进行的值计算未排序,则该行为未定义

书中的解释没有帮助我理解。左值到右值的转换与什么有关系?我做错了什么

。。。或使用同一标量对象的值进行值计算

重要的部分在这里用粗体表示。左侧不使用
i
的值进行值计算。正在计算的是一个glvalue。只有在之后(按顺序排列),才会触摸并替换对象的值


不幸的是,这是一个非常微妙的问题:)

这里的关键时刻是,
++i
的结果是一个左值。为了参与二进制
+
,必须通过左值到右值的转换将左值转换为右值。从左值到右值的转换基本上是从内存中读取变量
i

这意味着
++i
的值应该像直接从
i
读取一样获得。这意味着从概念上讲,在二进制
+
计算开始之前,
i
的新(递增)值必须准备就绪(必须物理存储在
i

这种额外的排序是无意中导致在本例中定义行为的原因

在C++03中,没有严格要求直接从
i
获取
++i
的值。新值可以被预测/预计算为
i+1
,并用作二进制
+
的操作数,甚至在它实际存储在
i
中之前。尽管可以合理地宣称,即使在C++03中,需求也隐含在那里(C++03不承认它的存在是C++03的一个缺陷)



对于
i++
,结果为右值。因为它已经是一个右值,所以不涉及左值到右值的转换,而且在我们开始评估二进制文件之前,绝对不需要将它存储在
i
+

很久以来,我一直在问这个问题,我写了一篇关于它的文章。这个问题与
i=++i
的情况相同,该问题在图表之前顺序如下:

红色节点表示
i
的副作用。蓝色节点表示使用
i
值的求值。此表达式定义良好的原因是,这些节点之间没有未排序的节点。使用assignment左侧的
i
不会使用
i
的值,因此这不是问题


我缺少的主要部分是“使用价值”的含义。如果运算符需要操作数的prvalue表达式,则使用该操作数的值。当给出一个对象的名称(即左值)时,左值必须进行从左值到右值的转换,这可以看作是“读取对象的值”。赋值只需要左操作数的左值,这意味着它不使用其值。

对“i”的值计算指向“ass”。这里计算的价值是什么?我不确定我是否理解那个图。@johanneschaub litb赋值的左操作数。从语句中可以看出:“在所有情况下,赋值都是在右操作数和左操作数的值计算之后,赋值表达式的值计算之前排序的。”@johanneschaub litb另外,它指向“ass”的唯一原因是因为在ASCII图中做对角线是一件很麻烦的事我想象它们是从中间分支出来的。@sftrabbit啊,现在我明白了:)也明白了,但这仍然不能使它按照
I
的值计算顺序排列,是吗?@sftrabbit:我不确定你的意思。你看,
++i
的结果有两个属性:1)它是一个左值,2)在数字上,它是
i
的新(递增)值。使这两个要求共存的唯一方法是要求在环绕表达式中进一步使用
++i
的结果之前,对
i
的修改进行排序。事实上,这种逻辑也适用于C++03,但C++03的目的是保持这种行为不被定义,因此C++03拒绝接受这种逻辑。预计对标准的进一步修改将使其保持UB,即,为了保持“UB自由”,标准中的其他内容将被重新设计在
i=++i+1
中,同时从
++i
规范中删除上述问题。然而,最终情况有所不同,在C++11中所做的更改实际上支持上述逻辑,而不是阻止它。因此,我们最终在
i=++i+1
中定义了行为,尽管没有人试图故意将此代码合法化。他希望“int i;i;”中的第二个语句将“使用同一标量对象的值进行值计算”,因此我们将有一个未排序的值计算和赋值“i”在他的示例表达式中。
i = ++i + 1
     ^
     |
assignment (side effect on i)
 ^      ^
 |      |
☆i   ++i + 1
     ||    ^
    i+=1   |
     ^     1
     |
★assignment (side effect on i)
  ^      ^
  |      |
  i      1