gpt4 book ai didi

c++ - gcc 4.6 和 4.7 之间的默认构造函数差异

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:43:44 27 4
gpt4 key购买 nike

在 GCC 4.6.1 上,当我声明一个具有默认构造函数的我自己类型的实例时,如果我实例化一个该类型的对象并用大括号(如 Foo my_foo{}; )初始化它,POD 成员如果没有声明其他构造函数,则该类中的将仅进行零初始化。如果除了默认构造函数之外没有其他构造函数,它们将像预期的那样进行零初始化。

但是,在 GCC 4.7.3 上,零初始化以任何一种方式发生,这是我预期的行为。

这里有什么区别?这是编译器错误吗?这两个 GCC 版本都支持 C++11 标准的默认构造函数。

没有真正需要坚持使用旧的 GCC 版本,但我想了解这里发生了什么。

注意:我默认了主构造函数 op=。并复制 ctor 只是为了保持类型可用于可变参数函数(clang 要求将类归类为 POD,尽管 gcc 让我摆脱了使用具有可变参数函数的类型,即使是用户定义的主 ctor。奖励积分如果你能告诉我为什么。)

这里有一个示例程序来说明,包括底部的一些输出(来自使用两个 GCC 版本编译的二进制文件):

#include <cstdio>

// pod and pod_wctor are identical except that pod_wctor defines another ctor

struct pod {
pod( void ) = default;
pod( const pod& other ) = default;
pod& operator=( const pod& other ) = default;

int x,y,z;
};

struct pod_wctor {
pod_wctor( void ) = default;
pod_wctor( const int setx, const int sety, const int setz ) : x(setx), y(sety), z(setz) { }
pod_wctor( const pod_wctor& other ) = default;
pod_wctor& operator=( const pod_wctor& other ) = default;

int x,y,z;
};

int main ( void ) {

printf("the following shuold be uninitialized:\n");

pod pee;
printf( " %i,%i,%i\n", pee.x, pee.y, pee.z);

pod_wctor podtor;
printf( " %i,%i,%i\n", podtor.x, podtor.y, podtor.z);

printf("the following shuold be initialized to 0,0,0:\n");

pod peenit{};
printf( " %i,%i,%i\n", peenit.x, peenit.y, peenit.z );

pod_wctor podtornit{};
printf( " %i,%i,%i\n", podtornit.x, podtornit.y, podtornit.z );

return 0;

}

// compiled with: g++ m.cpp -std=gnu++0x
// g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 (i386)
/****************** output *******************
the following shuold be uninitialized:
10381592,134513249,134520820
134513969,134513504,0
the following shuold be initialized to 0,0,0:
0,0,0
7367877,134513945,8724468
*********************************************/

// compiled with: g++ m.cpp -std=gnu++0x
// gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu4) (i386)
/****************** output *******************
the following shuold be uninitialized:
-1218358300,-1217268232,134520832
134514450,1,-1079827548
the following shuold be initialized to 0,0,0:
0,0,0
0,0,0
*********************************************/

最佳答案

通过将构造函数 pod_wctor( const int setx, const int sety, const int setz ) : x(setx), y(sety), z(setz) { } 添加到您的类中,它失去聚合状态:[dcl.init.aggregate]/1

An aggregate is an array or a class (Clause 9) with no user-provided constructors

它仍然是一个 POD,因为一个普通类只需要没有非普通的默认 ctors:[class]/6

A trivial class is a class that has a default constructor (12.1), has no non-trivial default constructors, and is trivially copyable.


这里有趣的一点是,对于聚合,列表初始化 pod peenit{}; 执行聚合初始化:

List-initialization of an object or reference of type T is defined as follows:

  • If T is an aggregate, aggregate initialization is performed (8.5.1). [...]
  • Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.

(注意:这是修改后的顺序。据我所知,在标准本身中,这两点的顺序是颠倒的,这一定是一个缺陷,因为每个聚合都有一个默认的构造函数——隐式声明和定义的构造函数。)

聚合初始化导致 int 成员的值初始化:[dcl.init.aggr]/7

If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list

and [dcl.init.list]/3 "否则,如果初始化列表没有元素,则对象被值初始化"


但是,对于非聚合pod_wctor,列表初始化pod_wctor podtornit{}直接执行值初始化,调用默认的ctor。 [class.ctor]/6 指定:

The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no ctor-initializer (12.6.2) and an empty compound-statement.

在 [class.base.init]/8 中,我们发现:

In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then

  • [...]
  • otherwise, the entity is default-initialized (8.5).

默认构造函数本身不保证成员清零,因为它只对成员进行默认初始化。


默认初始化和值初始化的区别:[dcl.init]

[7] To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type, the default constructor for T is called [...]
  • [...]
  • otherwise, no initialization is performed.

[...]

[8] To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type with either no default constructor or a default constructor that is user-provided or deleted, then the object is default-initialized;
  • if T is a (possibly cv-qualified) non-union class type without a user-provided or deleted default constructor, then the object is zero-initialized and, if T has a non-trivial default constructor, default-initialized;
  • [...]
  • otherwise, the object is zero-initialized.

(我承认这让我很困惑,我不得不修改我的答案。)

pod_wctor 有一个不是用户提供的默认构造函数。因此,对于列表初始化 pod_wctor podtornit{}value-initialization 的第二个项目符号适用。对象 podtornit 本身是零初始化,这导致其成员的零初始化。只有然后它才会被默认初始化,并且会调用默认的构造函数。后者什么也不做,但前者保证成员将被清零。

关于c++ - gcc 4.6 和 4.7 之间的默认构造函数差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18901315/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com