此代码是否会导致未定义的行为:
#include <vector>
struct S
{
S() {}
int x;
};
int main()
{
std::vector<S> vec(5, S());
}
由于S()
默认初始化自动对象,因此其内容不会首先归零,因此x
将是不确定的。然后将包含不确定值的对象复制到每个向量位置。
动机:我们可能期望这个行为与不是UB的std::vector<S> vec(5);
相同(因为C ++ 11),所以这是一个容易犯的错误。
正如Praetorian在评论中提到的那样,在C ++之前,std::vector<S> vec(5);
可以自由地进行5次默认初始化,或者对部分或全部项目使用复制构造函数。
答案 0 :(得分:4)
因此考虑OP的以下评论:
vector vec(5);不是UB(是吗?)我们倾向于认为(5)和 (5,S())也应该做同样的事情。我可以看到这个错误 很容易偶然发现。
问题归结为if:
vector<S> vec(5);
定义明确,原因是:
std::vector<S> vec(5, S());
未定义的行为?
如果我们转到std::vector::vector的cppreference部分,我们可以在第一种情况下看到它(自C ++ 11 )(强调我的):
使用计数默认插入的T实例构造容器。 没有制作副本。
而在第二种情况下:
使用值计数副本元素构造容器 值。
第一种情况将默认构造元素而不制作副本,而在第二种情况下将制作副本,因此我们最终将x
复制到每个元素。由于S
的默认构造函数未初始化x
,因此它将具有不确定值,因此我们有未定义的行为,因为生成不确定值调用未定义的行为。
由于C ++ 14部分8.5
段12
说:
如果评估产生了不确定的值,则表明该行为 除以下情况外,未定义
在 unsigned char 的情况下有一些例外,在这种情况下不适用。
我们知道x
具有来自同一段落的不确定值:
存储具有自动或动态存储持续时间的对象时 获得,对象具有不确定的值,如果没有 对象执行初始化,该对象保留一个 在替换该值之前不确定值
答案 1 :(得分:2)
TL; DR 是的,这是未定义的行为。
在您的代码中,您初始化临时值:
std::vector<S> vec(5, S());
// ^^^
来自§8.5/ 10:
一个对象,其初始化程序是一组空的括号,即
()
,应进行值初始化。
值初始化的定义是:
<强>第8.5节/ 8 强>
value-initialize
T
类型的对象意味着:- 如果
T
是一个(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或者是用户提供或删除的默认构造函数,那么该对象是默认的 - 初始化;- [..]
在这种情况下,值初始化不包括零初始化,因为S
具有用户声明的默认构造函数。所以它是默认构造的。
<强>第8.5节/ 7 强>
默认初始化
T
类型的对象意味着:- 如果
T
是(可能是cv限定的)类类型(第9节),则考虑构造函数。枚举适用的构造函数(13.3.1.3),并通过重载决策(13.3)选择初始化程序()
的最佳构造函数。使用空参数列表调用如此选择的构造函数来初始化对象。- 如果T是数组类型,则每个元素都是默认初始化的。
- 否则,不执行初始化。
由于你的默认构造函数没有显式初始化x
,所以它保持未初始化的垃圾值。默认的copy-constructor使用UB这些值初始化其他元素。
<强>第8.5节/ 12 强>
如果评估产生不确定的值,则行为未定义