TL; DR
给出以下代码:
int* ptr;
*ptr = 0;
Run Code Online (Sandbox Code Playgroud)
在应用间接之前,是否*ptr需要进行左值到右值的转换ptr?
该标准涵盖了许多地方的左值到左值的主题,但似乎没有指定足够的信息来确定*运算符是否需要这样的转换.
细节
在左值到右值的转换是覆盖在N3485的部分4.1 左值到右值转换段落1和说(重点矿山前进):
可以将非函数非数组类型T的glvalue(3.10)转换为prvalue.53如果T是不完整类型,则需要进行此转换的程序是错误的.如果glvalue引用的对象不是T类型的对象,并且不是从T派生的类型的对象,或者如果该对象未初始化,则需要此转换的程序具有未定义的行为.[...]
那么*ptr = 0; 转换需要吗?
如果我们转到4第1节,它说:
[...] 如果需要,标准转换序列将应用于表达式 ,以将其转换为所需的目标类型.
那么什么时候需要呢?如果我们看一下5 表达式,第9段中提到了左值到右值的转换,它说:
每当glvalue表达式作为操作符的操作数出现时,该操作符需要该操作数的prvalue,左值到右值(4.1),数组到指针(4.2)或函数到指针(4.3)标准转换是用于将表达式转换为prvalue.[...]
和第11段说:
在某些情况下,表达式仅出现其副作用.这样的表达式称为丢弃值表达式.[...]当且仅当表达式是volatile限定类型的左值并且它是以下之一时,才应用左值到右值转换(4.1). ...]
两段似乎都不适用于此代码示例和5.3.1 一元运算符第1段它说:
一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是指向表达式指向的对象或函数的左值.如果表达式的类型是"指向T的指针",则结果的类型为"T".[注意:通过指向不完整类型(cv void除外)的指向的间接有效.由此获得的左值可以以有限的方式使用(例如,初始化参考); 这个左值不能转换为prvalue,见4.1. - …
在标题为由于错误的strcmp参数处理而生成的警告之后,似乎存在一些关于标准实际上保证关于字符类型的值表示的问题.
这看起来很好,但标准是否保证(1)总是会产生真实的?
char unsigned * p1 = ...;
char * p2 = reinterpret_cast<char *> (p1);
*p1 == *p2; // (1)
Run Code Online (Sandbox Code Playgroud) 在关于未定义行为(UB)的许多讨论中,已经提出了这样的观点:在程序中存在任何具有UB的任何构造的程序都要求一致的实现做任何事情(包括什么都没有).我的问题是,即使在UB与代码执行相关联的情况下,是否应该采取这种方式,而标准中规定的行为(否则)规定不应执行相关代码(这可能是对于程序的特定输入;它可能在编译时不可判定).
更加非正式地说,UB的气味是否要求一致的实现来决定整个程序发臭,并且拒绝正确执行甚至行为完全明确定义的程序部分.一个示例程序将是
#include <iostream>
int main()
{
int n = 0;
if (false)
n=n++; // Undefined behaviour if it gets executed, which it doesn't
std::cout << "Hi there.\n";
}
Run Code Online (Sandbox Code Playgroud)
为清楚起见,我假设程序格式正确(因此特别是UB与预处理无关).事实上,我愿意将UB限制为与"评估"相关联,而"评估"显然不是编译时实体.我认为,与给出的例子相关的定义(重点是我的):
之前排序的是由单个线程(1.10)执行的评估之间的不对称,传递,成对关系,这导致这些评估之间的部分顺序
在运算符的结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于...或使用相同标量对象的值进行值计算未被排序,则行为未定义.
隐含地清楚的是,最后一句中的主语"副作用"和"价值计算"是"评价"的实例,因为这就是定义"之前排序"的关系.
我认为在上述程序中,标准规定不进行评价,以满足最后一句中的条件(相对于彼此和所描述的类型),并且该程序不具有UB; 这不是错误的.
换句话说,我确信我的标题问题的答案是否定的.但是,我会很感激其他人对此事的(动机)意见.
对于那些主张肯定答案的人来说,可能还有一个问题是,当编译错误的程序时,会强制重新格式化硬盘吗?
本网站上的一些相关指针:
我有这个大字符数组需要填充高频率的随机字节.我想知道除了天真的方式(使用for循环 - 用随机字节填充每个单元格)之外是否有更快的方法来执行此操作.对值的随机质量没有要求.任何"随机"垃圾都可以.平台是窗户
我试图std::swap从[C++ 11:utility.swap]中了解条件.模板定义为
template <typename T> void swap(T &, T &)
Run Code Online (Sandbox Code Playgroud)
(加上一些noexcept细节)并具有"交换存储在两个位置的值"的效果.
以下程序是否有明确定义?
#include <utility>
int main()
{
int m, n;
std::swap(m, n);
}
Run Code Online (Sandbox Code Playgroud)
如果我自己编写交换代码(即int tmp = m; m = n; n = tmp;),它将具有未定义的行为,因为它将尝试对未初始化的对象进行左值到右值的转换.但标准std::swap函数似乎没有任何强加于它的条件,也不能从规范中得出有任何左值到右值并因此有UB.
标准是否需要std::swap执行一些在未初始化对象上明确定义的魔法?
为了澄清这一点,请考虑函数void f(int & n) { n = 25; },该函数从未具有未定义的行为(因为它不读取n).
c++ undefined-behavior language-lawyer lvalue-to-rvalue c++11
我对以下代码感到困惑:
#include <iostream>
int i = 1;
int main()
{
int i = i;
std::cout << "i: " << i << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
i: 0
Run Code Online (Sandbox Code Playgroud)
我曾预计运行上面的代码会打印出来1.有人可以解释这种奇怪行为的原因吗?
前提:
C++ 11 Standard将表达式分为三个不相交的值类别:lvalues,xvalues和prvalues(第3.10/1节).此处提供了对哪些值类别的解释.
我正在努力弄清楚不同运营商对其操作数的价值类别的要求是什么.第3.10/1段规定:
[...]每个表达式都属于此分类法中的基本分类之一:lvalue,xvalue或prvalue.表达式的此属性称为其值类别.[注意:第5章中对每个内置运算符的讨论表明了它产生的值的类别以及它所期望的操作数的值类别.例如,内置赋值运算符期望左操作数是左值,右操作数是prvalue并产生左值作为结果.用户定义的运算符是函数,它们期望和产生的值的类别由它们的参数和返回类型决定. - 尾注]
尽管上面的说明声称,第5条并不总是非常清楚运营商的操作数的价值范畴.例如,关于赋值运算符的操作数的值类别(第5.17/1段),这就是所说的:
赋值运算符(=)和复合赋值运算符都是从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.对于不确定序列的函数调用,复合赋值的操作是单个评估.[注意:因此,函数调用不应介入左值到右值的转换和与任何单个复合赋值运算符相关的副作用. - 尾注]
合适的操作数怎么样?
整个5.17节中不再出现"rvalue"和"lvalue"字样.虽然第3.10/1段中的注释明确指出内置赋值运算符期望将prvalue作为右操作数,但在第5.17节中没有明确提到.甚至5.17/1的最后一个注释,提到左值到右值的转换,似乎暗示rvalues是以某种方式预期的(否则转换的需要是什么?),但笔记毕竟是非规范性的.
涉及其他运算符的部分,包括乘法运算符和加法运算符,通常对其操作数的值类别保持沉默.我在标准中找不到任何"默认语句",声明如果没有另外指定,内置运算符的操作数是rvalues.因此,问题.
题:
很高兴参考C++ 11标准.
我在c99标准中找到了这个
3.17.2
1 indeterminate value
either an unspecified value or a trap representation
Run Code Online (Sandbox Code Playgroud)
以上陈述对我来说并不清楚.任何人都可以解释这是什么,它的优点和缺点是什么?
一些例子将受到高度赞赏.
所以有点C++代码:
void func( const std::string& theString )
{
std::string theString( theString );
theString += " more string";
std::cout << theString;
}
Run Code Online (Sandbox Code Playgroud)
用GCC 4.8和编译好VS 2013.根据我的C++知识,代码是可以的,一个局部变量theString被带入范围,然后隐藏theString在函数参数中.在theString构造点,唯一theString的范围是传递给std::string构造函数的函数参数.std::string然后命名构造theString,它进入范围并theString在代码中稍后使用.唷!
但是,GCC似乎theString传递给std::string构造函数的行为是本地theString(尚未构造)导致编译的程序崩溃.使用VS 2013,代码编译并运行良好.
所以,