在C++ 03中,表达式是rvalue或lvalue.
在C++ 11中,表达式可以是:
两类已成为五大类.
正如初始化所述,需要进行左值到右值的转换?是int x = x;UB吗?C++标准在3.3.2 声明部分中有一个令人惊讶的例子,其中a int用它自己的不确定值初始化:
Run Code Online (Sandbox Code Playgroud)int x = 12; { int x = x; }这里第二个x用它自己的(不确定的)值初始化.- 结束例子 ]
Johannes对此问题的回答表明是未定义的行为,因为它需要左值到右值的转换.
在最新的C++ 14草案标准中N3936,可以在此处找到此示例已更改为:
Run Code Online (Sandbox Code Playgroud)unsigned char x = 12; { unsigned char x = x; }这里第二个x用它自己的(不确定的)值初始化.- 结束例子 ]
C++ 14中有关于不确定值和未定义行为的变化,这些变化在示例中引发了这种变化吗?
C++标准包含一个半着名的例子,在3.3.2中的"令人惊讶的"名称查找,"声明点":
int x = x;
Run Code Online (Sandbox Code Playgroud)
这初始化x自身,(原始类型)未初始化,因此具有不确定的值(假设它是一个自动变量).
这实际上是未定义的行为吗?
根据4.1"左值到右值转换",对未初始化的值执行左值到右值的转换是未定义的行为.右手是否x接受这种转换?如果是这样,示例实际上会有未定义的行为吗?
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. - …
我在c99标准中找到了这个
3.17.2
1 indeterminate value
either an unspecified value or a trap representation
Run Code Online (Sandbox Code Playgroud)
以上陈述对我来说并不清楚.任何人都可以解释这是什么,它的优点和缺点是什么?
一些例子将受到高度赞赏.
首先,我已经看到了关于C99的这个问题,并且接受的答案参考操作数未在C99标准草案中评估.我不确定这个答案是否适用于C++ 03.还有一个关于C++的问题,引用了类似措辞的答案,并且在某些情况下,还会出现未评估的操作数.未评估未评估的操作数.措辞.
我有这个代码:
int* ptr = 0;
void* buffer = malloc( 10 * sizeof( *ptr ) );
Run Code Online (Sandbox Code Playgroud)
问题是 - 里面是否有空指针取消引用(以及UB)sizeof()?
C++ 03 5.3.3/1表示sizeof运算符产生其操作数的对象表示中的字节数.操作数是表达式(未计算)或带括号的type-id.
链接到答案引用这个或类似的措辞,并使用"未评估"部分推断出没有UB.
但是,在这种情况下,我无法找到标准链接评估的确切位置与是否具有UB.
"不评估"应用sizeof的表达式使得在C++中取消引用sizeof中的null或无效指针是合法的吗?
这个问题出现在问题答案的评论中.当类型转换为int时,C/C++ bool类型总是保证为0或1吗?
有问题的代码在bool不初始化其值的情况下分配(本地)数组.
const int n = 100;
bool b[n];
Run Code Online (Sandbox Code Playgroud)
显然,价值观b是不确定的.
一些评论者认为阅读b[0]是不明确的行为.这是在C++标准中的任何地方陈述的吗?我仍然相信相反:
显然存储已分配,并且基本bool类型的初始化已完成,因为它没有构造函数.因此,它肯定与取消引用未初始化的指针或在未初始化的非平凡对象上调用方法/强制转换操作符不同.标准似乎涵盖了这些具体案例.
C中的行为确实未定义:C中声明的未初始化变量会发生什么?它有价值吗?一些受访者似乎对这两者感到困惑.
在最新的C++ 0x草案中,我找不到不确定值的定义,尤其是没有允许访问这样的值来触发处理器陷阱的定义.事实上,Bjarne的Stroustrup的是不知道的inderminate值可能是什么:http://zamanbakshifirst.blogspot.com/2007/02/c-indeterminate-value.html
我一直在互联网上阅读很多,似乎很多人提到了以下规则(但我在标准中找不到它),
加法运算符+(和所有其他二元运算符)要求两个操作数都是rvalue,结果是rvalue.等等..
我检查了C++标准,并明确指出(第3.10/2条),
每当glvalue出现在期望prvalue的上下文中时,glvalue就会转换为prvalue
(第5/9条),
每当glvalue表达式作为操作符的操作数出现时,该操作符需要该操作数的prvalue,左值到右值(4.1),数组到指针(4.2)或函数到指针(4.3)标准转换是用于将表达式转换为prvalue.
它使用一个术语操作数"期望"一个prvalue.但是,当我查看加法运算符,乘法运算符等时,它只提到,结果是一个prvalue,但它没有说明操作数是"预期"的内容.
二元运算符是否真的期望操作数是prvalue在以下情况下会有所不同,
int b = 2;
int a = b + 1;
Run Code Online (Sandbox Code Playgroud)
如果b预期是prvalue,那么这里将进行左值到右值的转换,然后它将执行prvalue + prvalue并返回一个prvalue,结果prvalue被赋值给一个左值a.
但是,如果b不需要是prvalue,则它将是lvalue + prvalue,结果是prvalue.
我真的想知道标准在哪里明确地或隐含地提到不同运营商的规则?我检查了所有运算符部分和只有少数运算符,标准明确提到操作数和结果是左值还是右值.对于大多数运营商而言,标准仅提及结果,而不是操作数要求.
谢谢.
顺便说一下,我在标准5.19中发现关于常量表达式可能非常"隐含地"暗示二元运算符需要对操作数进行左值到右值的转换.有关详细信息,请参阅我之前的问题,
条件表达式是常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2).
...
- 除非适用,否则为左值 - 右值转换(4.1)
----一个整数或枚举类型的glvalue,它引用一个带有前面初始化的非易失性const对象,用一个常量表达式初始化
谢谢阅读.
下面的代码是安全的,只要我没有读取结构数组的任何元素而不先设置实数值吗?谢谢.
const int data_size = 5;
struct Testing
{
int data[data_size];
Testing(const int data[data_size])
{
std::copy(data, data + data_size, this->data);
}
};
int main()
{
int data[data_size];
data[2] = 57;
Testing t(data);
t.data[1] = 93;
}
Run Code Online (Sandbox Code Playgroud) 我在这里使用N3936作为参考(如果任何C++ 14文本不同,请更正此问题).
在3.10 Lvalues和rvalues下,我们有:
每个表达式都属于此分类法中的基本分类之一:lvalue,xvalue或prvalue.
但是左值的定义是:
的左值 [...]表示一个功能或一个对象.
在4.1 Lvalue-to-rvalue转换中,文本显示:
[...]在所有其他情况下,转换的结果根据以下规则确定:[...]否则,glvalue指示的对象中包含的值是prvalue结果.
我的问题是:在左值不指定对象的代码中会发生什么?有两个典型的例子:
例1:
int *p = nullptr;
*p;
int &q = *p;
int a = *p;
Run Code Online (Sandbox Code Playgroud)
例2:
int arr[4];
int *p = arr + 4;
*p;
int &q = *p;
std::sort(arr, &q);
Run Code Online (Sandbox Code Playgroud)
哪些行(如果有的话)格式不正确和/或导致未定义的行为?
参考实施例1:是*p左值?根据我的第一句话,它必须是.但是,我的第二个引文排除了它,因为*p没有指定一个对象.(它肯定不是xvalue或prvalue).
但是如果你将我的第二个引用解释*p为实际上是一个左值,那么它就不会被左值到右值转换规则所覆盖.您可以采用全部规则"标准未定义的任何内容是未定义的行为",但是只要没有执行左值到右值的转换,就必须允许空引用存在.
历史:此问题在DR 232中提出.在C++ 11中,DR232的分辨率确实出现了.引用N3337 Lvalue -to-rvalue转换:
如果glvalue引用的对象不是类型T的对象,并且不是从T派生的类型的对象,或者如果对象未初始化,则需要此转换的程序具有未定义的行为.
它似乎仍然允许空引用存在 - 它只清除了在一个上执行左值到右值转换的问题.也讨论了这个SO线程
DR232的分辨率不再出现在N3797或N3936中.
我目前正在阅读本教程/ rvalue参考的解释:
http://thbecker.net/articles/rvalue_references/section_07.html
在第二段到最后一段中,作者提到" 工厂主体中T的复制构造函数的论证是一个左值 ".他所指的代码是这样的:
template<typename T, typename Arg>
shared_ptr<T> factory(Arg const & arg)
{
return shared_ptr<T>(new T(arg));
}
Run Code Online (Sandbox Code Playgroud)
我意识到new T(arg)在堆上构造一个T对象,但是返回的值不是一个临时指针值,如果不使用它会丢失(导致内存泄漏),因此是一个rvalue?
编辑:只是为了澄清,我知道在这个例子中将没有内存泄漏.我的意思是,如果指针值没有被使用,我们将无法访问构造的T对象,因此我们会得到内存泄漏.
我在c ++中做了一个基本的"猜我的数字游戏",并且我添加了一个变量,用于猜测这个数字需要多少猜测.然而,当游戏结束时,显示猜测的随机值.像1980046322这样的东西.考虑到我没有在我的代码中添加任何特别的内容,我无法弄清楚为什么会这样做.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
int randomNumber;
int guess;
int guesses;
srand((unsigned)time(0));
randomNumber = (rand()%10)+1;
cout << "I am thinking of a number between 1 to 10. Can you guess it?" << endl;
while(guess != randomNumber){
cout << "That is not correct, try again.";
guesses++;
cin >> guess;
}
if(guess == randomNumber){
cout << "Good Job. Guesses: " << guesses << endl;
guesses++;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 有许多声称使用未初始化的变量会调用未定义的行为(UB).
仔细阅读文档,我无法验证该声明,因此我想要一个令人信服的论据,为C和C++澄清这一点.
我期望两者都有相同的语义,但我准备对微妙或不那么微妙的差异感到惊讶.
使用未初始化变量开始的一些示例.请根据需要添加其他人,以解释他们未涵盖的任何角落案例.
void test1() {
int x;
printf("%d", x);
}
void test2() {
int x;
for(int i = 0; i < CHAR_BIT * sizeof x)
x = x << 1;
printf("%d", x);
}
void test3() {
unsigned x;
printf("%u", x); /* was format "%d" */
}
void test4() {
unsigned x;
for(int i = 0; i < CHAR_BIT * sizeof x)
x = x << 1;
printf("%u", x); /* was format "%d" */
}
Run Code Online (Sandbox Code Playgroud) c++ ×11
lvalue ×3
c ×2
c++11 ×2
c++14 ×2
rvalue ×2
c++-faq ×1
expression ×1
indirection ×1
int ×1
new-operator ×1
null-pointer ×1
pointers ×1
random ×1
sizeof ×1