默认初始化和值初始化结构的性能不同

时间:2016-07-04 21:58:04

标签: c++ arrays initialization

我有一个带数组的简单结构:

template<class T>
void testDefault()
{
  T* pa = new T;  // Default
  use(*pa);
  delete pa;
}

template<class T>
void testValue()
{
  T* pa = new T();  // Value
  use(*pa);
  delete pa;
}

我有两个函数,使用默认初始化和值初始化创建它:

struct A
{
  uint32_t arr[size];
  // Implicit constructor
};

struct B
{
  uint32_t arr[size];
  B() {};  // Empty constructor
};

struct C
{
  uint32_t arr[size];
  C() = default;  // Defaulted constructor
};

我面对这些功能的不同表现。有趣的是,性能差异取决于我如何声明结构的默认构造函数。我有三种方式:

testDefault()

我认为从编译器的角度来看它们都是一样的。从来没有我这么错。我确实使用结构testValue()AB多次运行CDefault initialization (implict constructor) done in 880ms Value initialization (implict constructor) done in 1145ms Default initialization (empty constructor) done in 867ms Value initialization (empty constructor) done in 865ms Default initialization (defaulted constructor) done in 872ms Value initialization (defaulted constructor) done in 1148ms 并测量了性能。这就是我所拥有的:

{{1}}

请注意隐式和默认构造函数的性能明显更差。只有空构造函数才能正确显示两种不同初始化表单的相同性能。

我用VC ++,gcc和clang测试了这个。见online demo for gcc。时间很持久。

我认为是:

  1. UDT的默认值和值初始化是一回事
  2. 定义默认构造函数的所有演示方法都在做同样的事情
  3. 这些结构的默认构造函数应该使数组的内容处于不确定状态
  4. 由于所有编译器都表现出相同的时序,似乎我错过了一些东西。有人可以解释一下这些时间吗?

    (另请参阅关于同一主题的问题Why compilers put zeros into arrays while they do not have to?。我在那里提供了一些指向cppreference的链接。)

2 个答案:

答案 0 :(得分:5)

让我们看一下 value-initialize 的定义:

  

对T类型的对象进行值初始化意味着:

     
      
  • 如果T是一个(可能是cv限定的)类类型,没有默认构造函数(12.1)或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;
  •   
  • 如果T是(可能是cv限定的)类类型而没有用户提供或删除的默认构造函数,则该对象为零初始化[...];
  •   
  • 如果T是数组类型,则每个元素都是值初始化的;
  •   
  • 否则,该对象为零初始化。
  •   

另外,让我们回顾这里使用的形容词:

  • 用户声明 - 您声明了构造函数
  • 用户提供 - 您声明了构造函数,但未将其设置为= default= delete
  • 默认 - 可以不带参数调用
  • 声明为默认 - 标记为= default;或隐式生成

查看你的课程:

  • A有一个默认构造函数,它被隐式声明为默认值,而不是用户提供的。
  • C有一个默认构造函数,用户声明为默认构造函数,而不是用户提供的。

因此,value-initialize定义中的第二个要点适用。该对象为零初始化,意味着arr被清零。

  • B有一个默认构造函数,由用户提供。

因此,value-initialize的第一个要点适用于B;值初始化与此处的默认初始化相同,arr未归零。

您的时间安排似乎与预期相符:AC的值初始化为arr,而其他情况则为{<1}}。

答案 1 :(得分:2)

其中一个构造函数在值初始化时表现不同。在这个版本中,

B() {};

B::arrB时,数组B::arr未进行值初始化。和其他人一样。这是否能解释性能差异是另一回事。

因此,A::arr不会通过值初始化进行零初始化,而C::arrarr会进行初始化。所有三种情况在默认初始化下都具有相同的行为,也就是说,<div id="popup">Hello World!</div> 获取默认初始化,即不执行初始化。