Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 首先调用哪个构造函数_C++_Exception_Constructor - Fatal编程技术网

C++ 首先调用哪个构造函数

C++ 首先调用哪个构造函数,c++,exception,constructor,C++,Exception,Constructor,以下代码来自中的“异常处理”。作者试图告诉我们,通过将一切都变成对象,我们可以防止资源泄漏。 我的问题: 为什么调用“cat”和“dog”的构造函数要早于调用“useresources”的构造函数 //: C07:Wrapped.cpp // Safe, atomic pointers #include <fstream> #include <cstdlib> using namespace std; ofstream out("wrapped.out"); // Sim

以下代码来自中的“异常处理”。作者试图告诉我们,通过将一切都变成对象,我们可以防止资源泄漏。 我的问题: 为什么调用“cat”和“dog”的构造函数要早于调用“useresources”的构造函数

//: C07:Wrapped.cpp
// Safe, atomic pointers
#include <fstream>
#include <cstdlib>
using namespace std;
ofstream out("wrapped.out");
// Simplified. Yours may have other arguments.
template<class T, int sz = 1> class PWrap {
    T* ptr;
public:
    class RangeError {}; // Exception class
    PWrap() {
        ptr = new T[sz];
        out << "PWrap constructor" << endl;
    }
    ~PWrap() {
        delete []ptr;
        out << "PWrap destructor" << endl;
    }
    T& operator[](int i) throw(RangeError) {
        if(i >= 0 && i < sz) return ptr[i];
        throw RangeError();
    }
};
class Cat {
public:
    Cat() { out << "Cat()" << endl; }
    ~Cat() { out << "~Cat()" << endl; }
    void g() {}
};
class Dog {
public:
    void* operator new[](size_t sz) {
        out << "allocating an Dog" << endl;
        throw int(47);
    }
    void operator delete[](void* p) {
        out << "deallocating an Dog" << endl;
        ::delete p;
    }
};
class UseResources {
    PWrap<Cat, 3> Bonk;
    PWrap<Dog> Og;
public:
    UseResources() : Bonk(), Og() {
        out << "UseResources()" << endl;
    }
    ~UseResources() {
        out << "~UseResources()" << endl;
    }
    void f() { Bonk[1].g(); }
};
int main() {
    try {
        UseResources ur;
    } catch(int) {
        out << "inside handler" << endl;
    } catch(...) {
    out << "inside catch(...)" << endl;
    }
} ///:~
/:C07:Wrapped.cpp
//安全的原子指针
#包括
#包括
使用名称空间std;
流出(“包裹的”);
//简化的。你可能有其他的论点。
模板类PWrap{
T*ptr;
公众:
类范围错误{};//异常类
PWrap(){
ptr=新T[sz];
出来
为什么调用“cat”和“dog”的构造函数要早于调用“useresources”的构造函数

//: C07:Wrapped.cpp
// Safe, atomic pointers
#include <fstream>
#include <cstdlib>
using namespace std;
ofstream out("wrapped.out");
// Simplified. Yours may have other arguments.
template<class T, int sz = 1> class PWrap {
    T* ptr;
public:
    class RangeError {}; // Exception class
    PWrap() {
        ptr = new T[sz];
        out << "PWrap constructor" << endl;
    }
    ~PWrap() {
        delete []ptr;
        out << "PWrap destructor" << endl;
    }
    T& operator[](int i) throw(RangeError) {
        if(i >= 0 && i < sz) return ptr[i];
        throw RangeError();
    }
};
class Cat {
public:
    Cat() { out << "Cat()" << endl; }
    ~Cat() { out << "~Cat()" << endl; }
    void g() {}
};
class Dog {
public:
    void* operator new[](size_t sz) {
        out << "allocating an Dog" << endl;
        throw int(47);
    }
    void operator delete[](void* p) {
        out << "deallocating an Dog" << endl;
        ::delete p;
    }
};
class UseResources {
    PWrap<Cat, 3> Bonk;
    PWrap<Dog> Og;
public:
    UseResources() : Bonk(), Og() {
        out << "UseResources()" << endl;
    }
    ~UseResources() {
        out << "~UseResources()" << endl;
    }
    void f() { Bonk[1].g(); }
};
int main() {
    try {
        UseResources ur;
    } catch(int) {
        out << "inside handler" << endl;
    } catch(...) {
    out << "inside catch(...)" << endl;
    }
} ///:~
在输入
UseResources
的构造函数的主体之前调用它们

UseResources
有两个数据成员,它们是
PWrap
类模板的实例化。
PWrap
的构造函数实例化了许多类型为
T
的对象:

ptr = new T[sz];
从而导致对
T
Cat
Dog
,在您的情况下)的构造函数进行相应次数的调用

自从pReS> /Cord>对象是 UsReSurvis<代码>的数据成员,它们的构造函数在 UsSeReSux<代码>的构造函数之前被执行。这就是对象构造在C++中如何工作。

这背后的基本原理是确保在输入构造函数主体时,所有子对象(包括基本子对象和成员子对象-例如
Bonk
Og
)的构造函数都已完成

通过这种方式,构造函数可以依赖于使用有效的子对象,这些子对象的类不变量在执行时已经建立

这是C++11标准第12.6.2/10段描述过程的方式:

在非委托构造函数中,初始化按以下顺序进行:

-首先,并且仅对于派生最多的类(1.8)的构造函数,虚拟基类在 它们在基类的有向无环图的深度优先的从左到右遍历中出现的顺序, 其中“从左到右”是派生类基类说明符列表中基类的出现顺序

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

-然后,按照类定义中声明的顺序初始化非静态数据成员 (同样,不考虑mem初始值设定项的顺序)

-最后,执行构造函数主体的复合语句

[注意:声明顺序的任务是确保在中销毁基子对象和成员子对象 初始化的相反顺序。-结束注释]

为什么调用“cat”和“dog”的构造函数要早于调用“useresources”的构造函数

//: C07:Wrapped.cpp
// Safe, atomic pointers
#include <fstream>
#include <cstdlib>
using namespace std;
ofstream out("wrapped.out");
// Simplified. Yours may have other arguments.
template<class T, int sz = 1> class PWrap {
    T* ptr;
public:
    class RangeError {}; // Exception class
    PWrap() {
        ptr = new T[sz];
        out << "PWrap constructor" << endl;
    }
    ~PWrap() {
        delete []ptr;
        out << "PWrap destructor" << endl;
    }
    T& operator[](int i) throw(RangeError) {
        if(i >= 0 && i < sz) return ptr[i];
        throw RangeError();
    }
};
class Cat {
public:
    Cat() { out << "Cat()" << endl; }
    ~Cat() { out << "~Cat()" << endl; }
    void g() {}
};
class Dog {
public:
    void* operator new[](size_t sz) {
        out << "allocating an Dog" << endl;
        throw int(47);
    }
    void operator delete[](void* p) {
        out << "deallocating an Dog" << endl;
        ::delete p;
    }
};
class UseResources {
    PWrap<Cat, 3> Bonk;
    PWrap<Dog> Og;
public:
    UseResources() : Bonk(), Og() {
        out << "UseResources()" << endl;
    }
    ~UseResources() {
        out << "~UseResources()" << endl;
    }
    void f() { Bonk[1].g(); }
};
int main() {
    try {
        UseResources ur;
    } catch(int) {
        out << "inside handler" << endl;
    } catch(...) {
    out << "inside catch(...)" << endl;
    }
} ///:~
在输入
UseResources
的构造函数的主体之前调用它们

UseResources
有两个数据成员,它们是
PWrap
类模板的实例化。
PWrap
的构造函数实例化了许多类型为
T
的对象:

ptr = new T[sz];
从而导致对
T
Cat
Dog
,在您的情况下)的构造函数进行相应次数的调用

自从pReS> /Cord>对象是 UsReSurvis<代码>的数据成员,它们的构造函数在 UsSeReSux<代码>的构造函数之前被执行。这就是对象构造在C++中如何工作。

这背后的基本原理是确保在输入构造函数主体时,所有子对象(包括基本子对象和成员子对象-例如
Bonk
Og
)的构造函数都已完成

通过这种方式,构造函数可以依赖于使用有效的子对象,这些子对象的类不变量在执行时已经建立

这是C++11标准第12.6.2/10段描述过程的方式:

在非委托构造函数中,初始化按以下顺序进行:

-首先,并且仅对于派生最多的类(1.8)的构造函数,虚拟基类在 它们在基类的有向无环图的深度优先的从左到右遍历中出现的顺序, 其中“从左到右”是派生类基类说明符列表中基类的出现顺序

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

-然后,按照类定义中声明的顺序初始化非静态数据成员 (同样,不考虑mem初始值设定项的顺序)

-最后,执行构造函数主体的复合语句

[注意:声明顺序的任务是确保在中销毁基子对象和成员子对象 初始化的相反顺序。-结束注释]

在代码段中:

   UseResources() : Bonk(), Og() {
      out << "UseResources()" << endl;
   }
UseResources():Bonk(),Og(){
代码段中的out:

   UseResources() : Bonk(), Og() {
      out << "UseResources()" << endl;
   }
UseResources():Bonk(),Og(){

out构造函数调用的顺序是:

  • 基类
  • 成员,按其在标题中出现的顺序排列
  • 类构造函数
  • 类UseResources是在调用构造函数主体之前“构造”的,因为它具有大小,并且成员变量具有正确的地址。但是它们尚未完全构造

    构造函数的主体可以假定其所有成员都是alr