C++ 中是否有隐式默认构造函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/563221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:58:28  来源:igfitidea点击:

Is there an implicit default constructor in C++?

c++constructor

提问by Skilldrick

In the book I'm reading at the moment (C++ Without Fear) it says that if you don't declare a default constructor for a class, the compiler supplies one for you, which "zeroes out each data member". I've experimented with this, and I'm not seeing any zeroing -out behaviour. I also can't find anything that mentions this on Google. Is this just an error or a quirk of a specific compiler?

在我目前正在阅读的书(C++ Without Fear)中,它说如果你没有为类声明默认构造函数,编译器会为你提供一个,它“将每个数据成员归零”。我已经对此进行了试验,但没有看到任何归零行为。我也无法在 Google 上找到任何提及此内容的内容。这只是特定编译器的错误还是怪癖?

采纳答案by Martin York

If you do not define a constructor, the compiler will define a default constructor for you.

如果你没有定义构造函数,编译器会为你定义一个默认的构造函数。

The implementation of this

本次实施

default constructor is:

默认构造函数是:

  • default construct the base class (if the base class does not have a default constructor, this is a compilation failure)
  • default construct each member variable in the order of declaration. (If a member does not have a default constructor, this is a compilation failure).
  • 默认构造基类(如果基类没有默认构造函数,这是编译失败)
  • 默认按照声明的顺序构造每个成员变量。(如果成员没有默认构造函数,则这是编译失败)。

Note:
The POD data (int,float,pointer, etc.) do not have an explicit constructor but the default action is to do nothing (in the vane of C++ philosophy; we do not want to pay for something unless we explicitly ask for it).

注意:
POD 数据(int、float、pointer 等)没有显式构造函数,但默认操作是什么都不做(在 C++ 哲学的风向标中;除非我们明确要求,否则我们不想为某些东西付费它)。

If no destructor/copy Constructor/Assignment operator is defined the compiler builds one of those for you (so a class always has a destructor/Copy Constructor/Assignment Operator (unless you cheat and explicitly declare one but don't define it)).
The default implementation is:

如果没有定义析构函数/复制构造函数/赋值运算符,编译器会为您构建其中一个(因此类始终具有析构函数/复制构造函数/赋值运算符(除非您作弊并明确声明但未定义它))。
默认实现是:

Destructor:

析构函数:

  • If user-defined destructor is defined, execute the code provided.
  • Call the destructor of each member in reverse order of declaration
  • Call the destructor of the base class.
  • 如果定义了用户定义的析构函数,则执行提供的代码。
  • 以与声明相反的顺序调用每个成员的析构函数
  • 调用基类的析构函数。

Copy Constructor:

复制构造函数:

  • Call the Base class Copy Constructor.
  • Call the copy constructor for each member variable in the order of declaration.
  • 调用基类复制构造函数。
  • 按照声明的顺序为每个成员变量调用复制构造函数。

Assignment Operator:

赋值运算符:

  • Call the base class assignment operator
  • Call the assignment operator of each member variable in the order of declaration.
  • Return a reference to this.
  • 调用基类赋值运算符
  • 按照声明的顺序调用每个成员变量的赋值运算符。
  • 返回对此的引用。

Note Copy Construction/Assignment operator of POD Data is just copying the data (Hence the shallow copy problem associated with RAW pointers).

注意 POD 数据的复制构造/赋值运算符只是复制数据(因此存在与 RAW 指针相关的浅拷贝问题)。

回答by Bill the Lizard

I think it's worth pointing out that the default constructor will only be created by the compiler if you provide no constructor whatsoever. That means if you only provide one constructor that takes an argument, the compiler will notcreate the default no-arg constructor for you.

我认为值得指出的是,如果您不提供任何构造函数,则默认构造函数只会由编译器创建。这意味着如果您只提供一个带参数的构造函数,编译器将不会为您创建默认的无参数构造函数。

The zeroing-out behavior that your book talks about is probably specific to a particular compiler. I've always assumed that it can vary and that you should explicitly initialize any data members.

您的书中谈到的归零行为可能特定于特定的编译器。我一直认为它可以变化并且您应该显式初始化任何数据成员。

回答by nobar

  • Does the compiler automatically generate a default constructor?
  • Does the implicitly generated default constructor perform zero initialization?
  • 编译器会自动生成默认构造函数吗?
  • 隐式生成的默认构造函数是否执行零初始化?

If you legalistically parse the language of the 2003 standard, then the answers are yes, and no. However, this isn't the whole storybecause unlike a user-defined default constructor, an implicitly defined default constructor is not always usedwhen creating an object from scratch -- there are two other scenarios: no constructionand member-wise value-initialization.

如果您合法地解析 2003 标准的语言,那么答案是yesno。然而,这并不是全部,因为与用户定义的默认构造函数不同,从头开始创建对象时并不总是使用隐式定义的默认构造函数——还有另外两种情况:无构造成员值初始化.

The "no construction" case is really just a technicality because it is functionally no different than calling the trivialdefault constructor. The other case is more interesting: member-wise value-initialization is invoked by using "()" [as if explicitly invoking a constructor that has no arguments] and it bypasses what is technically referred to as thedefault constructor. Instead it recursively performs value-initialization on each data member, and for primitive data types, this ultimately resolves to zero-initialization.

“无构造”的情况实际上只是一个技术问题,因为它在功能上与调用平凡的默认构造函数没有什么不同。另一种情况是更加有趣:成员明智值初始化通过使用调用“()” [仿佛明确调用一个没有参数的构造函数]和它绕过什么技术上称为默认构造函数。相反,它递归地对每个数据成员执行值初始化,对于原始数据类型,这最终会解析为零初始化

So in effect, the compiler provides two different implicitly defined default constructors. One of which doesperform zero initialization of primitive member data and the other of which does not. Here are some examples of how you can invoke each type of constructor:

所以实际上,编译器提供了两个不同的隐式定义的默认构造函数。其中一个确实执行原始成员数据的零初始化,而另一个则不执行。以下是如何调用每种类型的构造函数的一些示例:

    MyClass a; // default-construction or no construction
    MyClass b = MyClass(); // member-wise value-initialization

and

    new MyClass; // default-construction or no construction
    new MyClass(); // member-wise value-initialization

Note: If a user-declareddefault constructor doesexist, then member-wise value-initialization simply calls that and stops.

注意:如果用户声明的默认构造函数确实存在,则成员值初始化简单地调用它并停止。



Here's a somewhat detailed breakdown of what the standard says about this...

以下是标准对此的详细说明......

  • If you don't declare a constructor, the compiler implicitly creates a default constructor [12.1-5]

  • The default constructor does notinitialize primitive types [12.1-7]

    MyClass() {} // implicitly defined constructor
    
  • If you initialize an object with "()", this does not directly invoke the default constructor. Instead, it instigates a long sequence of rules called value-initialization[8.5-7]

  • The net effect of value initialization is that the implicitly declared default constructor is never called. Instead, a recursive member-wise value initialization is invoked which will ultimately zero-initialize any primitive membersand calls the default constructor on any members which have a user-declared constructor [8.5-5]

  • Value-initialization applies even to primitive types -- they will be zero-initialized. [8.5-5]

    a = int(); // equivalent to int a=0;
    
  • 如果不声明构造函数,编译器会隐式创建一个默认构造函数 [12.1-5]

  • 默认构造函数不初始化原始类型 [12.1-7]

    MyClass() {} // implicitly defined constructor
    
  • 如果使用“()”初始化对象,则不会直接调用默认构造函数。相反,它引发了一系列称为值初始化的规则[8.5-7]

  • 值初始化的净效果是隐式声明的默认构造函数永远不会被调用。取而代之的是,一个递归的成员值初始化被调用,这将最终将任何原始成员初始化为零,并在具有用户声明的构造函数的任何成员上调用默认构造函数 [8.5-5]

  • 值初始化甚至适用于原始类型——它们将被零初始化。[8.5-5]

    a = int(); // equivalent to int a=0;
    


All of this is really moot for most purposes. The writer of a class cannot generally assume that data members will be zeroed out during an implicit initialization sequence -- so any self-managing class should define its own constructor if it has any primitive data members that require initialization.

对于大多数目的而言,所有这些都没有实际意义。类的编写者通常不能假设在隐式初始化序列期间数据成员将被清零——因此,如果任何自管理类有任何需要初始化的原始数据成员,则它应该定义自己的构造函数。

So when does this matter?

那么这什么时候重要?

  • There may be circumstances where generic code wants to force initialization of unknown types. Value-initialization provides a way to do this. Just remember that implicit zero-initialization does not occur if the user has provided a constructor.

  • By default, data contained by std::vector is value-initialized. This can prevent memory debuggers from identifying logic errors associated with otherwise uninitialized memory buffers.

    vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
    
  • Entire arrays of primitives type or "plain-old-data" (POD)-type structures can be zero-initialized by using value-initialization syntax.

    new int[100]();
    
  • 可能存在通用代码想要强制初始化未知类型的情况。值初始化提供了一种方法来做到这一点。请记住,如果用户提供了构造函数,则不会发生隐式零初始化。

  • 默认情况下, std::vector 包含的数据是值初始化的。这可以防止内存调试器识别与未初始化的内存缓冲区相关的逻辑错误。

    vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
    
  • 可以使用值初始化语法对原始类型或“普通旧数据”(POD) 类型结构的整个数组进行零初始化。

    new int[100]();
    


This posthas more details about variations between versions of the standard, and it also notes a case where the standard is applied differently in major compilers.

这篇文章提供了有关标准版本之间变化的更多详细信息,并且还指出了标准在主要编译器中的应用不同的情况。

回答by Todd Gamblin

C++ does generate a default constructor but only if you don't provide one of your own. The standard says nothing about zeroing out data members. By default when you first construct any object, they're undefined.

C++ 确实会生成默认构造函数,但前提是您不提供自己的构造函数。该标准没有说明将数据成员归零。默认情况下,当您第一次构造任何对象时,它们是未定义的。

This might be confusing because most of the C++ primitive types DO have default "constructors" that init them to zero (int(), bool(), double(), long(), etc.), but the compiler doesn't call them to init POD members like it does for object members.

这可能会令人困惑,因为大多数 C++ 原始类型确实具有将它们初始化为零的默认“构造函数”(int()、bool()、double()、long()),但编译器不调用他们像对对象成员一样初始化 POD 成员。

It's worth noting that the STL doesuse these constructors to default-construct the contents of containers that hold primitive types. You can take a look at this questionfor more details on how things in STL containers get inited.

值得注意的是,STL确实使用这些构造函数来默认构造包含基本类型的容器的内容。您可以查看此问题以获取有关如何初始化 STL 容器中的内容的更多详细信息。

回答by Eclipse

The default constructor created for a class will not initialize built-in types, but it will call the default constructor on all user-defined members:

为类创建的默认构造函数不会初始化内置类型,但会在所有用户定义的成员上调用默认构造函数:

class Foo
{
public:
     int x;
     Foo() : x(1) {}
};

class Bar
{
public:
     int y;
     Foo f;
     Foo *fp;
};

int main()
{

    Bar b1; 
    ASSERT(b1.f.x == 1); 
    // We know nothing about what b1.y is set to, or what b1.fp is set to.

    // The class members' initialization parallels normal stack initialization.
    int y;  
    Foo f; 
    Foo *fp; 
    ASSERT(f.x == 1);
    // We know nothing about what y is set to, or what fp is set to.

}

回答by Andrew Grant

The compiler will generate default constructors and destructors if user-created ones are not present. These will NOT modify the state of any data members.

如果不存在用户创建的构造函数和析构函数,编译器将生成默认构造函数和析构函数。这些不会修改任何数据成员的状态。

In C++ (and C) the contents of any allocated data is not guaranteed. In debug configurations some platforms will set this to a known value (e.g. 0xFEFEFEFE) to help identify bugs, but this should not be relied upon.

在 C++(和 C)中,不保证任何分配数据的内容。在调试配置中,某些平台会将其设置为已知值(例如 0xFEFEFEFE)以帮助识别错误,但不应依赖于此。

回答by codelogic

Zero-ing out only occurs for globals. So if your object is declared in the global scope, its members will be zero-ed out:

归零只发生在全局变量中。因此,如果您的对象在全局范围内声明,则其成员将被清零:

class Blah
{
public:
    int x;
    int y;
};

Blah global;

int main(int argc, char **argv) {
    Blah local;
    cout<<global.x<<endl;  // will be 0
    cout<<local.x<<endl;   // will be random
}

回答by Jason Cohen

C++ does notguarantee zeroing out memory. Java and C# do (in a manner of speaking).

C ++并不能保证归零内存。Java 和 C# 可以(从某种意义上说)。

Some compilers might, but don't depend on that.

一些编译器可能会,但不依赖于此。

回答by Nice Books

In C++11, a default constructor generated by the compiler is marked deleted , if :

在 C++11 中,编译器生成的默认构造函数被标记为已删除,如果:

  • the class has a reference field
  • or a const field without a user-defined default constructor
  • or a field without a default initializer, with a deleted default constructor
  • 该类有一个参考字段
  • 或没有用户定义的默认构造函数的 const 字段
  • 或没有默认初始值设定项的字段,带有删除的默认构造函数

http://en.cppreference.com/w/cpp/language/default_constructor

http://en.cppreference.com/w/cpp/language/default_constructor

回答by Jason Punyon

C++ generates a default constructor. If needed (determined at compile time I believe), it will also generate a default copy constructor and a default assignment constructor. I haven't heard anything about guarantees for zeroing memory though.

C++ 生成默认构造函数。如果需要(我相信在编译时确定),它还将生成一个默认的复制构造函数和一个默认的赋值构造函数。不过,我还没有听说过关于将内存归零的任何保证。