Chr*_*eck 8 c++ undefined-behavior language-lawyer lvalue-to-rvalue c++14
在C++ 14标准(n3797)中,左值转换的左值部分如下所示(强调我的):
4.1左值 - 右值 - 转换[conv.lval]
T可以将非函数非数组类型的glvalue(3.10)转换为prvalue.如果T是不完整类型,则需要进行此转换的程序格式不正确.如果T是非类类型,则prvalue的类型是cv-nonqualified versionT.否则prvalue的类型是T.当在未评估的操作数或其子表达式中发生左值到右值转换时(第5条),不访问引用对象中包含的值.在所有其他情况下,转换结果根据以下规则确定:
- 如果
T是(可能是cv限定的)std::nullptr_t则结果是空指针常量.- 否则,如果
T有类类型,则转换复制 -T从glvalue 初始化一个临时类型,转换的结果是临时的prvalue.- 否则,如果glvalue引用的对象包含无效指针值,则行为是实现定义的.
- 否则,如果
T是(可能是cv限定的)无符号字符类型,并且glvalue引用的对象包含不确定的值,并且该对象没有自动存储持续时间,或者glvalue是一元运算&符的操作数,或者它是绑定到引用,结果是一个未指定的值.- 否则,如果glvalue引用的对象具有不确定的值,则行为未定义.
- 否则,glvalue指示的对象是prvalue结果.
- [ 注:另见3.10]
这一段有什么意义(粗体)?
如果此段落不在此处,那么它适用的情况将导致未定义的行为.通常,我希望unsigned char在具有不确定值时访问值会导致未定义的行为.但是,这一段意味着
&或将其绑定到引用,或者unsigned char没有自动存储时间,然后转换产生一个未指定的值,而不是未定义的行为.
我是否正确地得出这个程序的结论:
#include <new>
#include <iostream>
// using T = int;
using T = unsigned char;
int main() {
T * array = new T[500];
for (int i = 0; i < 500; ++i) {
std::cout << static_cast<int>(array[i]) << std::endl;
}
delete[] array;
}
Run Code Online (Sandbox Code Playgroud)
是由标准明确定义,并且必须输出500个未指定的整数序列,而同一个程序在哪里T = int,会有未定义的行为?
IIUC是使UB读取具有不确定值的事物的原因之一,是允许优化器消除积极的死存储.因此,这一段可能意味着符合标准的编译器在使用unsigned char或数组时不能做那么多的优化unsigned char.
假设我理解正确,这条规则的基本原理是什么?何时能够读取unsigned char具有不确定值的值并获得未指定的结果而不是UB是否有用?我有这种感觉,如果他们付出这么多努力来制定规则的这一部分,他们有一些动机来帮助他们关心的某些代码示例,或者与标准的其他部分保持一致,或者简化其他一些问题.但我不知道那可能是什么.
在许多情况下,代码会写入 PODS 或数组的某些部分,而不写入所有内容,然后使用memcpy或 等函数fwrite复制或写入整个内容,而不考虑哪些部分已分配值,哪些部分未分配值。尽管 C++ 代码使用基于字节的操作来复制或写出聚合的内容并不常见,但这样做的能力是该语言的基本部分。要求程序将确定的值写入对象的所有部分,包括那些永远不会“关心”的部分,会不必要地降低效率。
| 归档时间: |
|
| 查看次数: |
168 次 |
| 最近记录: |