簡體   English   中英

C ++中的對象創建和銷毀順序

[英]Object creation and destruction order in C++

我編寫了一個簡單的程序,以了解有關在C ++中創建和銷毀對象的順序的更多信息(使用Visual Studio 2015)。 這里是:

#include <iostream>
#include <string>

using namespace std;

class A
{
public:
    A(string name)
        : name(name)
    {
        cout << "A(" << name << ")::constructor()" << endl;
    }
    ~A()
    {
        cout << "A(" << name << ")::destructor()" << endl;
    }
private:
    string name;
};

class C
{
public:
    C(string name, A a)
        : name(name), a(a)
    {
        cout << "C(" << name << ")::constructor()" << endl;
    }
    ~C()
    {
        cout << "C(" << name << ")::destructor()" << endl;
    }
private:
    string name;
    A a;
};

class B
{
public:
    B(string name)
        : name(name)
    {
        cout << "B(" << name << ")::constructor()" << endl;
    }
    ~B()
    {
        cout << "B(" << name << ")::destructor()" << endl;
    }
private:
    string name;
    A a1{"a1"};
    A a2{"a2"};
    C c1{"c1", a1};
    A a3{"a3"};
};

int main()
{
    B b("b1");
    return 0;
}

輸出使我有些驚訝( a1 s):

A(a1)::constructor()
A(a2)::constructor()
C(c1)::constructor()
A(a1)::destructor()
A(a3)::constructor()
B(b1)::constructor()
B(b1)::destructor()
A(a3)::destructor()
C(c1)::destructor()
A(a1)::destructor()
A(a2)::destructor()
A(a1)::destructor()

要了解發生了什么,我添加了有關對象實例的信息:

    A(string name)
        : name(name)
    {
        cout << "A(" << name << ")::constructor(), this = " << this << endl;
    }
    ~A()
    {
        cout << "A(" << name << ")::destructor(), this = " << this << endl;
    }

結果更加令人驚訝:

A(a1)::constructor(), this = 0039FB28
A(a2)::constructor(), this = 0039FB44
C(c1)::constructor()
A(a1)::destructor(), this = 0039F8A8
A(a3)::constructor(), this = 0039FB98
B(b1)::constructor()
B(b1)::destructor()
A(a3)::destructor(), this = 0039FB98
C(c1)::destructor()
A(a1)::destructor(), this = 0039FB7C
A(a2)::destructor(), this = 0039FB44
A(a1)::destructor(), this = 0039FB28

即,為什么a1的構造函數僅被調用一次,而析構函數僅被調用3次 我傳遞a按值,因此顯然至少創建了一個臨時對象,但是請向我解釋何時以及創建和銷毀了多少個 A實例?

正如注釋中已經指出的那樣,當您通過值將其作為參數傳遞時,也會通過復制構造來構造A類型A對象。 為了看到這一點,您可以自己添加一個復制構造函數:

A(const A& other)
: name(other.name)
{
    cout << "A(" << name << ")::copy-constructor(), this = " << this << endl;
}

樣本輸出:

A(a1)::constructor(), this = 0xbff3512c
A(a2)::constructor(), this = 0xbff35130
A(a1)::copy-constructor(), this = 0xbff350e8
A(a1)::copy-constructor(), this = 0xbff35138
C(c1)::constructor()
A(a1)::destructor(), this = 0xbff350e8
A(a3)::constructor(), this = 0xbff3513c
B(b1)::constructor()
B(b1)::destructor()
A(a3)::destructor(), this = 0xbff3513c
C(c1)::destructor()
A(a1)::destructor(), this = 0xbff35138
A(a2)::destructor(), this = 0xbff35130
A(a1)::destructor(), this = 0xbff3512c

在線嘗試

如您所見,當您將a1作為參數傳遞給c1的構造函數時,將發生一種復制構造,而當此構造函數初始化其成員a時,將發生另一種復制構造。 此后,臨時副本將在銷毀后立即銷毀,而在銷毀c時銷毀成員。

編輯:
在這里,您可以閱讀創建復制構造函數時的確切規則。
為了不創建默認的復制構造函數,僅提供用戶定義的構造函數是不夠的,它必須是復制/移動構造函數。

編輯2:

取自C ++ 14標准(12.8復制和移動類對象):

7如果類定義未顯式聲明一個副本構造函數,則隱式聲明一個副本構造函數。 如果類定義聲明了move構造函數或move賦值運算符,則隱式聲明的copy構造函數將定義為delete; 否則,將其定義為默認值(8.4)。 如果該類具有用戶聲明的副本分配運算符或用戶聲明的析構函數,則不建議使用后者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM