big*_*iao 14 c++ undefined-behavior language-lawyer
例如:
#include<iostream>
using namespace std;
int main() {
int i = i=0; //no warning
cout << i << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在vs2015中编译,没有警告和输出0
.这个代码片段是否定义明确,虽然看起来有点奇怪?
但是,在这个在线编译器(g++ prog.cc -Wall -Wextra -std=c++17
)中它会抛出一个警告:
prog.cc: In function '`int main()`':
prog.cc:8:12: warning: operation on '`i`' may be undefined [-Wsequence-point]
`int i=i=0;`
Run Code Online (Sandbox Code Playgroud)
Ben*_*igt 13
有两种可能的情况,取决于对象的生命周期是否已经开始.这取决于第一条规则[basic.life]
:
对象或引用的生命周期是对象或引用的运行时属性.如果一个对象属于类或聚合类型,并且它或其子对象之一由除了普通默认构造函数之外的构造函数初始化,则称该对象具有非空的初始化.[注意:通过简单的复制/移动构造函数进行初始化是非空的初始化.- 结尾注释]类型对象的生命周期
T
从以下开始:
- 获得具有适当对齐和类型大小的存储
T
,并且- 如果对象具有非空的初始化,则其初始化完成,除非对象是联合成员或其子对象,其生命周期仅在该联合成员是联合中的初始化成员或(如(
[class.union]
)中所述)时开始.
类或聚合类型的对象
std::string s = std::to_string(s.size()); // UB
Run Code Online (Sandbox Code Playgroud)
在这种情况下,在初始化完成之前,对象的生命周期才会开始,因此此规则[basic.life]
适用:
类似地,在对象的生命周期开始之前但在对象将占用的存储已经被分配之后,或者在对象的生命周期结束之后并且在对象占用的存储被重用或释放之前,任何引用的glvalue之前可以使用原始对象,但仅限于有限的方式.对于正在建造或销毁的物体,请参阅(
[class.cdtor]
).否则,这样的glvalue指的是分配的存储,并且使用不依赖于其值的glvalue的属性是很好的定义.如果出现以下情况,该程
- glvalue用于访问对象,或
- glvalue用于调用对象的非静态成员函数,或
- glvalue绑定到对虚基类的引用,或
- glvalue用作a
dynamic_cast
的操作数或作为操作数的操作数typeid
.
在此示例中,glvalue用于访问非静态成员,从而导致未定义的行为.
原始类型的对象
int i = (i=0); // ok
int k = (k&0); // UB
Run Code Online (Sandbox Code Playgroud)
这里,即使有初始化器,由于类型的原因,初始化也不能是非空的.因此,对象的生命周期已经开始,上述规则不适用.
仍然,对象中的现有值是不确定的(除非对象具有静态存储持续时间,在这种情况下,静态初始化为其赋值为零).引用具有不确定值的对象的glvalue绝不能进行左值到右值的转换.因此,"只写"操作是允许的,但大多数1个操作读不确定的值导致不确定的行为.
适用的规则见[dcl.init]
:
如果没有为对象指定初始化程序,则默认初始化该对象.当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,并且如果没有对该对象执行初始化,则该对象保留不确定的值,直到该值被替换.[注意:具有静态或线程存储持续时间的对象是零初始化的,请参阅(
[basic.start.static]
). - 结束说明]如果评估产生不确定的值,则行为未定义,但以下情况除外:
如果
std::byte
通过以下评估产生无符号窄字符类型或类型的不确定值:
- 条件表达式的第二个或第三个操作数,
- 逗号表达式的右操作数,
- 转换的操作数或转换为无符号窄字符类型或
std::byte
类型,或- 丢弃值表达式,
那么操作的结果就是一个不确定的值.
- 如果
std::byte
通过评估一个简单赋值运算符的右操作数产生无符号窄字符类型或类型的不确定值,该操作符的第一个操作数是无符号窄字符类型或std :: byte类型的左值,则不确定值将替换为左操作数引用的对象.- 如果在初始化无符号窄字符类型的对象时通过初始化表达式的求值产生无符号窄字符类型的不确定值,则该对象被初始化为不确定的值.
- 如果
std::byte
在初始化std::byte
类型的对象时通过初始化表达式的求值产生无符号窄字符类型或类型的不确定值,则该对象被初始化为不确定的值.
1使用字符类型复制不确定的值有一个很小的例外,使目标值也不确定.该值仍然不能用于其他操作,如按位运算符或算术运算.
归档时间: |
|
查看次数: |
636 次 |
最近记录: |