当前位置: 首页 > 知识库问答 >
问题:

对空的用户定义构造函数将如何初始化非静态非POD成员变量感到困惑

岳均
2023-03-14

我知道非POD类型的默认初始化也会通过调用它们的默认构造函数默认初始化非静态非POD成员变量。但我不确定这到底是如何发生的。这是我的意思的一个例子:

#include <iostream>
#include <vector>
using namespace std;

class Test2 {
  public:
    Test2() {cout <<"Here";}
};

class Test {
  public:
    Test() {}
    Test2 i;
};

int main() {
  Test foo;
}

输出为:

Here

基于初始化器上的C标准(8.5),对于默认初始化:

— if T is a non-POD class type (clause 9), the default constructor
for T is called (and the initialization is ill-formed if T has no
accessible default constructor);

因此,我确实希望调用默认构造函数,但类Test的空默认构造函数并没有显式地初始化Test2 I,而是隐式地调用。我想知道这是怎么发生的?

类似地,对于值初始化(与上面的示例无关),如果空用户定义的默认构造函数没有显式地将POD非静态成员变量初始化为零,那么该变量如何获得零初始化(我知道它确实如此)?由于基于标准,似乎对于值初始化,当您拥有用户定义的默认构造函数时发生的一切就是构造函数被调用。

值初始化的C标准的相应部分如下:

— if T is a class type (clause 9) with a user-declared constructor (12.1), then the   
default constructor for T is called (and the initialization is ill-formed if T has no 
accessible default constructor);

这个问题类似于c空构造函数和成员初始化,但不同的是,我不想问最终结果行为是什么,而是想知道为什么会发生最终结果行为。

共有3个答案

濮阳国兴
2023-03-14

根据C标准草案http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf,第12.6.2节:

如果给定的非静态数据成员或基类不是由mem初始值设定项id命名的(包括由于构造函数没有ctor初始值设定项而没有mem初始值设定项列表的情况),则

-如果实体是(可能是cv限定的)类类型(或其数组)或基类的非静态数据成员,并且实体类是非POD类,则实体默认初始化(8.5)。如果实体是常量限定类型的非静态数据成员,则实体类应具有用户声明的默认构造函数。

-否则,实体未初始化。如果实体是const限定类型或引用类型,或者(可能是cv限定的)POD类类型(或其数组)包含(直接或间接)const限定类型的成员,则程序格式错误。

换句话说,如果非POD类类型的对象没有出现在初始值设定项列表中,编译器会将其解释为该对象出现时调用了其默认构造函数。

另外,请注意,其他类型(即原语和POD类型)没有初始化,这与您在问题中指出的不同。全局对象初始化为零,但堆栈上的对象不是这样。下面是我编写的一个小程序来测试这一点:

#include <iostream>

class T
{
public:
    T() {}

    void put(std::ostream &out)
    {
        out << "a = " << a << std::endl;
        out << "b = " << b << std::endl;
        out << "c = " << c << std::endl;
    }
private:
    int a;
    int b;
    int c;
};

T t2;

int main()
{
    T t;
    t.put(std::cout);
    t2.put(std::cout);

    return 0;
}

使用g 4.5.2编译,我得到了以下输出:

a = 8601256
b = 3
c = 2130567168
a = 0
b = 0
c = 0
元英朗
2023-03-14

如果非静态POD成员未在构造函数中显式初始化,则具有用户定义的默认构造函数的类型的值初始化不会对其执行初始化。E、 g.在本程序中:

#include <iostream>

using namespace std;

struct Foo {
    // Foo has a user-defined default constructor
    // that does not initialize i
    Foo() {}
    int i;
};

int main() {
    Foo x{}; // value-initialize x
    cout << x.i << endl;
}

x. i未初始化。因此,该程序在技术上具有未定义的行为,但在这种情况下,“未定义的行为”很可能意味着它将打印一个可能不是0的未指定整数值。

语言律师论据:

  • §12.6.1p2:“类类型的对象也可以由带括号的初始化列表初始化。列表初始化语义适用;见8.5和8.5.4。”
东郭臻
2023-03-14

在C 11标准第12.6节第8段中:

在非委托构造函数中,如果给定的非静态数据成员或基类不是由mem初始值设定项id指定的(包括由于构造函数没有ctor初始值设定项而没有mem初始值设定项列表的情况),并且实体不是抽象类(10.4)的虚拟基类,则

  • 如果实体是具有大括号或相等初始值设定项的非静态数据成员,则该实体按照8.5中的规定进行初始化

您遇到了第三种情况,其中没有成员的初始值设定项,并且成员不是变体成员,因此在这种情况下,它是默认初始化的。

此外,根据第10段:

在非委托构造函数中,初始化按以下顺序进行:-首先,并且仅对于最底层的派生类(1.8)的构造函数,虚拟基类的初始化顺序是它们出现在基类的有向无环图的深度优先从左到右遍历上,其中“从左到右”是基类在派生类base-规范-列表中的出现顺序。

  • 然后,直接基类按照它们在基说明符列表中出现的声明顺序进行初始化(无论mem初始化器的顺序如何)

无论在构造函数中指定什么,都将在执行构造函数体之前初始化成员。

mem初始化器id是用于引用构造函数初始化器列表中的成员的标识符:

class Test {
  public:
    Test() : i() {} // Here `i` is a mem-initializer-id
    Test2 i;
};
 类似资料:
  • 如果我有一个简单的结构Foo,定义如下,它是一个POD: 现在想象一下,我想默认初始化成员并直接执行以下操作: 结构不再是吊舱!即使有这样的构造函数: Foo已经失去了它的PODness... 现在,棘手的部分开始了。想象一下,我想添加一个构造函数,取一个: 现在,傅绝对不是一个豆荚。但如果添加默认构造函数: 福现在是一个豆荚! 因此,正如您所看到的,即使我只是想使用第二个示例中的默认值,我也会失

  • 问题内容: 我有两个班,第一个是我的主班,第二个是我的编辑框架班。 我的第二个类(UpdateGUI)在其构造函数中提供oldName,并对其进行编辑,当我单击时,它将newName发送给我的第一个类。 我的第二堂课: 我的问题是,为什么newName为null? 更新: UpdateGUIDialog类: 输出: 我需要打印而不是null。 问题答案: Java对象有点像真实对象。并顾名思义:它

  • 本文向大家介绍PHP静态成员变量和非静态成员变量详解,包括了PHP静态成员变量和非静态成员变量详解的使用技巧和注意事项,需要的朋友参考一下 数据成员可以分静态变量、非静态变量两种. 静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员存在于

  • 本文向大家介绍C ++静态成员变量及其初始化,包括了C ++静态成员变量及其初始化的使用技巧和注意事项,需要的朋友参考一下 静态C ++成员变量是使用static关键字定义的。类中的静态成员变量由所有类对象共享,因为在内存中只有它们的一个副本,而与该类的对象数量无关。 如果没有以任何其他方式初始化静态类成员变量,则在创建类的第一个对象时将其初始化为零。 给出了一个演示静态成员变量及其在C ++中的

  • 在C 11之前,我们只能对整型或枚举类型的静态常量成员执行类内初始化。Stroustrup在他的C FAQ中对此进行了讨论,并给出了以下示例: 以及以下推理: 那么,为什么会存在这些不便的限制呢?类通常在头文件中声明,头文件通常包含在许多翻译单元中。然而,为了避免复杂的链接器规则,C要求每个对象都有一个唯一的定义。如果C允许在类中定义需要作为对象存储在内存中的实体,那么这个规则就会被打破。 但是,

  • 问题内容: 我有以下代码: 这给了我以下错误: 解析错误:语法错误,在第19行的/home/user/Sites/site/registration/inc/registration.class.inc中出现意外的’(’,期待’)’ 所以,我想我做错了什么…但是如果不那样做怎么办?如果我用常规字符串更改mktime内容,它将起作用。所以,我知道我能做到这一点 的那种 像.. 有人有指针吗? 问题答