包含未初始化值的对象矢量

时间:2014-12-30 03:06:16

标签: c++ initialization stdvector undefined-behavior

此代码是否会导致未定义的行为:

#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次默认初始化,或者对部分或全部项目使用复制构造函数。

2 个答案:

答案 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.512说:

  

如果评估产生了不确定的值,则表明该行为   除以下情况外,未定义

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

     

如果评估产生不确定的值,则行为未定义