简体   繁体   English

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

[英]Different performance for default initialized and value initialized struct

I have a simple struct with an array: 我有一个带数组的简单结构:

struct A
{
  uint32_t arr[size];
};

I have two functions, which create it using default initialization and value 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;
}

I'm facing different performance for those functions. 我面临着这些功能的不同表现。 The funny thing is that performance differences vary depending on how I declare default constructor of the struct. 有趣的是,性能差异取决于我如何声明结构的默认构造函数。 I have three ways: 我有三种方式:

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
};

I thought they are all the same from compiler's point of view. 从编译器的角度来看,我认为它们都是一样的。 Never have been I so wrong. 从来没有我这么错。 I did run both testDefault() and testValue() several times with structs A , B and C and measured performance. 我确实用结构ABC运行了testDefault()testValue()几次并测量了性能。 Here is what I have: 这是我有的:

Default 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

Note how performance is clearly worse for both implicit and defaulted constructors. 注意隐式和默认构造函数的性能如何明显更差。 Only empty constructor correctly shows the same performance for both different initialization forms. 只有空构造函数才能正确显示两种不同初始化表单的相同性能。

I tested this with VC++, gcc and clang. 我用VC ++,gcc和clang测试了这个。 See online demo for gcc . 请参阅gcc的在线演示 Timings are quite persistent. 时间非常持久。

What I assume is: 我假设是:

  1. Default and value initializations for UDT are the same thing UDT的默认值和值初始化是相同的
  2. All demonstrated ways of defining default constructor are doing the same thing 所有已经证明的定义默认构造函数的方法都在做同样的事情
  3. Default constructor of these structs should leave content of the array in indeterminate state 这些结构的默认构造函数应该使数组的内容处于不确定状态

Since all the compilers exhibit the same timings, it seems like I'm missing something. 由于所有编译器都表现出相同的时序,似乎我错过了一些东西。 Can anyone please explain me these timings? 有人可以解释一下这些时间吗?

(See also my question Why compilers put zeros into arrays while they do not have to? on the same topic. I give some links to cppreference there.) (另请参阅我的问题为什么编译器将零放入数组而不必使用?在同一主题上。我在那里提供了一些指向cppreference的链接。)

Let's look at the definition of value-initialize : 让我们看一下value-initialize的定义:

To value-initialize an object of type T means: 对值类型T的对象进行值初始化意味着:

  • if T is a (possibly cv-qualified) class type with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized; 如果T是一个(可能是cv限定的)类类型,没有默认构造函数(12.1)或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;
  • if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized [...]; 如果T是一个(可能是cv限定的)类类型而没有用户提供或删除的默认构造函数,那么该对象是零初始化的[...];
  • if T is an array type, then each element is value-initialized; 如果T是数组类型,那么每个元素都是值初始化的;
  • otherwise, the object is zero-initialized. 否则,该对象被零初始化。

Also let's review the adjectives in use here for constructors: 另外,让我们回顾一下构造函数在这里使用的形容词:

  • user-declared - you declared the constructor user-declared - 您声明了构造函数
  • user-provided - you declared the constructor and didn't set it to = default or = delete user-provided - 您声明了构造函数,但未将其设置为= default= delete
  • default - can be called with no arguments default - 可以不带参数调用
  • declared as defaulted - marked = default; 声明为默认值 - 标记= default; or implicitly generated as such 或隐含地生成

Looking at your classes: 看你的课程:

  • A has a default constructor which is implicitly declared as defaulted, and not user-provided. A有一个默认构造函数,它被隐式声明为默认值,而不是用户提供的。
  • C has a default constructor which is user-declared as defaulted, and not user-provided. C有一个默认构造函数,用户声明为默认构造函数,而不是用户提供的构造函数。

So the second bullet point in the definition of value-initialize applies. 因此,value-initialize定义中的第二个要点适用。 The object is zero-initialized, meaning the arr is zeroed out. 该对象是零初始化的,这意味着arr被清零。

  • B has a default constructor which is user-provided. B有一个用户提供的默认构造函数。

So the first bullet point of value-initialize applies to B ; 所以value-initialize的第一个要点适用于B ; value-initialization is the same as default-initialization here, and arr is not zeroed out. value-initialization与此处的default-initialization相同,并且arr不会被清零。

Your timings correctly seem to correspond to what is expected: value-initialization of A or C zeroes out arr and the other cases don't. 你的时间正确地看起来与预期相符: AC值初始化将arr排除在外,而其他情况则不然。

One of the constructors behaves differently under value initialization. 其中一个构造函数在值初始化下表现不同。 In this version, 在这个版本中,

B() {};

the array B::arr is not value-initialized when the B is. B是时,数组B::arr没有进行值初始化。 With the others, it is. 和其他人一样。 Whether this explains the performance difference is another matter. 这是否解释了性能差异是另一回事。

So, B::arr doesn't get zero-initialized with value initialization, whereas A::arr and C::arr do. 因此, B::arr不会通过值初始化进行零初始化,而A::arrC::arr可以。 All three cases have the same behaviour under default initialization, that is to say, arr gets default-initialized , ie no initialization is performed. 所有三种情况在默认初始化下都具有相同的行为,也就是说, arr得到默认初始化 ,即不执行初始化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM