C++ 对象构造语义学——局部对象、全局对象的构造和析构
局部对象、全局对象的构造和析构
局部对象、全局对象的构造和析构
- 局部对象、全局对象的构造和析构
- 1. 局部对象的构造和析构
- 示例代码
- 2. 全局对象的构造和析构
- 理解要点
- 示例代码
- 3. 实际应用中的考虑
- 总结
1. 局部对象的构造和析构
-
构造:
- 局部对象在其作用域内创建时,会自动调用构造函数。这一过程确保对象在使用前被正确初始化。
- 在函数内部创建的对象,其生命周期仅限于该函数的执行。
-
析构:
- 当局部对象的作用域结束时,编译器会自动插入代码调用对象的析构函数,从而确保资源的有效释放。
- 局部对象的析构函数在其作用域结束时被自动调用。
-
成员变量初始化:
- 当创建一个类的对象时,成员变量(如
m_i
)的初始值是随机的。 - 局部对象的成员变量在创建时并不会自动初始化,若未显式赋值,其值将是未定义的。
- 为了确保对象的稳定性和可预测性,程序员应在构造函数的初始化列表或构造函数体内为其显式赋值。
- 当创建一个类的对象时,成员变量(如
示例代码
#include <iostream>class MyClass {
public:int m_i;MyClass() : m_i(0) { // 为 m_i 赋初值std::cout << "构造函数被调用,m_i = " << m_i << std::endl;}~MyClass() {std::cout << "析构函数被调用" << std::endl;}
};void function() {MyClass localObj; // 局部对象// localObj 的析构函数会在作用域结束时被调用
}int main() {function(); // 调用函数return 0;
}
2. 全局对象的构造和析构
-
构造:
- 全局对象在程序启动时创建,其构造函数在
main
准备执行之前被调用。 - 全局对象在整个程序运行期间始终可用,适合需要在多个函数间共享的资源。
- 全局对象在程序启动时创建,其构造函数在
-
析构:
- 全局对象在程序结束时销毁,其析构函数在
main
执行完毕后被调用。
- 全局对象在程序结束时销毁,其析构函数在
-
成员变量初始化:
- 全局对象的成员变量(如数值类型)如果没有显式赋值,编译器会默认初始化为0,这与局部对象不同。
理解要点
- 程序执行流程:
- 程序在进入
main
函数之前以及执行完main
函数之后会进行许多其他操作。程序并不只是从main
开始执行,也并不在返回main
后立即结束。
- 程序在进入
- 编译器插入的代码:
- 编译器会在程序中插入代码以处理全局对象的静态初始化和析构。例如,在
main
开始前会调用全局对象的构造函数,在main
结束后会调用析构函数。
- 编译器会在程序中插入代码以处理全局对象的静态初始化和析构。例如,在
示例代码
#include <iostream>class MyClass {
public:int m_i;MyClass() : m_i(0) { // 全局对象的成员变量初始化为0std::cout << "全局对象构造函数被调用,m_i = " << m_i << std::endl;}~MyClass() {std::cout << "全局对象析构函数被调用" << std::endl;}
};MyClass globalObj; // 全局对象int main() {std::cout << "进入 main 函数" << std::endl;return 0;
}
3. 实际应用中的考虑
在实际开发中,选择使用局部对象还是全局对象取决于具体需求:
- 局部对象:适合于临时使用的资源,能够有效地控制资源的生命周期,避免全局状态带来的复杂性。
- 全局对象:适合于需要在多个函数间共享的资源,但使用不当可能导致意想不到的副作用,如全局状态的变化影响程序的其他部分。
总结
- 局部对象:在作用域内构造和析构,成员变量需显式初始化。
- 全局对象:在程序启动和结束时构造和析构,成员变量默认初始化为0。