c++ - 首先调用哪个构造函数

标签 c++ exception constructor

以下代码来自 .作者试图告诉我们,通过将一切都变成对象,我们可以防止资源泄漏。 我的问题: 为什么'cat'和'dog'的构造函数比'userresources'的构造函数更早被调用?

//: 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;
    }
} ///:~

最佳答案

Why the constructors of 'cat' and 'dog' are called earlier than constructor of 'useresources'?

它们的调用早于输入 UseResources 的构造函数的主体

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

ptr = new T[sz];

从而导致对 T 的构造函数进行相应数量的调用(在您的情况下为 CatDog )。

由于 PWrap 对象是 UseResources 的数据成员,因此它们的构造函数会在输入 UseResources 构造函数的主体之前执行。这就是 C++ 中对象构造的工作原理。

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

这样,构造函数可以依赖使用有效的子对象,这些子对象的类不变量在执行时已经建立。

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

In a non-delegating constructor, initialization proceeds in the following order:

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

Finally, the compound-statement of the constructor body is executed.

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note ]

关于c++ - 首先调用哪个构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16033729/

相关文章:

c++ - int main() 首先在这里定义错误

c++ - 没有可调用的匹配函数

c++ - 制作复制构造函数

constructor - Perl6 : Constructors in subclases

c++ - GLFW 洋红色导致意外行为

c++ - 确定合并排序中边数组的大小

'Microsoft.TeamFoundation.Framework.Server.ByteArray' 的类型初始值设定项引发的异常

Java:new Properties(...) 和 new Properties().putAll(...) 之间的区别

swift - 转换到另一个 View Controller 时,应用程序崩溃而没有有关崩溃的信息

c# - "using"语句中出现异常,WCF 未正确关闭连接。如何关闭有故障的 WCF 客户端连接或有异常的连接?