C++四大构造函数,析构函数详解以及代码示例
2023-12-24 10:35:45
构造函数与析构函数
构造函数是用来初始化对象的成员变量的特殊函数。当创建类的新对象时,构造函数会被自动调用。构造函数的名称与类名相同,并且没有返回类型。一个类可以有多个构造函数,这被称为构造函数的重载。析构函数是当对象的生命周期结束时自动调用的特殊函数,用于执行清理操作,如释放资源、内存等。析构函数的名称由波浪号(~)后跟类名组成,并且没有参数和返回类型。
#include <iostream>
class SimpleClass {
private:
int number; // 数据成员
public:
// 默认构造函数
SimpleClass() : number(0) { // 初始化为0
std::cout << "Default constructor called for object at [" << this << "], number = " << number << std::endl;
}
// 参数化构造函数
SimpleClass(int num) : number(num) { // 初始化为传入的值
std::cout << "Parameterized constructor called for object at [" << this << "], number = " << number << std::endl;
}
// 拷贝构造函数
SimpleClass(const SimpleClass& other) : number(other.number) { // 通过复制来初始化
std::cout << "Copy constructor called for object at [" << this << "], number = " << number << std::endl;
}
// 移动构造函数
SimpleClass(SimpleClass&& other) noexcept : number(other.number) { // 通过移动来初始化
other.number = 0; // 移动后,将源对象的数据成员设置为默认值
std::cout << "Move constructor called for object at [" << this << "], number = " << number << std::endl;
}
// 析构函数
~SimpleClass() {
std::cout << "Destructor called for object at [" << this << "], number was " << number << std::endl; // 使用this指针
}
};
int main() {
std::cout << "Creating object with default constructor:" << std::endl;
SimpleClass obj1;
std::cout << "\nCreating object with parameterized constructor:" << std::endl;
SimpleClass obj2(42);
std::cout << "\nCreating object with copy constructor:" << std::endl;
SimpleClass obj3 = obj2;
std::cout << "\nCreating object with move constructor:" << std::endl;
SimpleClass obj4 = std::move(obj2); // obj2的内容现在已经移动到obj4,obj2不应再被使用
std::cout << "\nExiting main function, objects will be destroyed in reverse order of creation." << std::endl;
return 0; // 对象会按照创建的相反顺序被销毁: obj4, obj3, obj2, obj1
}
输出结果:
Creating object with default constructor:
Default constructor called for object at [0x61ff0c], number = 0
Creating object with parameterized constructor:
Parameterized constructor called for object at [0x61ff08], number = 42
Creating object with copy constructor:
Copy constructor called for object at [0x61ff04], number = 42
Creating object with move constructor:
Move constructor called for object at [0x61ff00], number = 42
Exiting main function, objects will be destroyed in reverse order of creation.
Destructor called for object at [0x61ff00], number was 42
Destructor called for object at [0x61ff04], number was 42
Destructor called for object at [0x61ff08], number was 0
Destructor called for object at [0x61ff0c], number was 0
在上方的代码中,SimpleClass 类包含了一个整型成员 number 和四种构造函数以及一个析构函数:
- 默认构造函数:没有参数,将 number 初始化为0,并打印出相关信息。
- 参数化构造函数:接受一个整数参数,并用该参数初始化number,然后打印出相关信息。
- 拷贝构造函数:接受一个 SimpleClass 类型的常量引用作为参数,用其 number成员初始化新对象的 number成员,并打印出相关信息。
- 移动构造函数:接受一个 SimpleClass 类型的右值引用作为参数,将其number 成员的值移动到新对象,并将原对象的 number 成员设为0,然后打印出相关信息。
- 析构函数:打印出对象被销毁的信息,并显示number 成员的值。
在 main 函数中,创建了四个 SimpleClass 类型的对象,每个对象都使用不同的构造函数。随后,在程序退出时,这些对象按照创建的相反顺序被销毁,析构函数被调用,并打印出相关信息。
注意,由于 obj2 的内容被移动到了 obj4,所以 obj2 的 number 成员在析构时是0。
对比拷贝构造函数和移动构造函数
- 拷贝构造函数:
拷贝构造函数用于创建一个类的对象作为另一个同类型对象的副本。它接受一个同类型对象的引用作为参数。拷贝构造函数通常执行深拷贝,即不仅复制对象的值,还复制对象所拥有的资源(如动态分配的内存)。这种构造函数对于管理动态资源和避免悬挂指针问题非常重要。 - 移动构造函数:
移动构造函数是C++11引入的新特性,用于支持对象的移动语义。移动构造函数接受一个同类型对象的右值引用作为参数。它允许资源的所有权从一个对象转移到另一个对象,通常涉及指针的简单交换和避免不必要的资源复制。移动构造函数可以显著提高性能,特别是在处理大型对象或资源密集型对象时。
#include <iostream>
#include <chrono>
class Vector {
private:
int* data;
size_t size;
public:
Vector(size_t n) : size(n) {
data = new int[size];
for (size_t i = 0; i < size; ++i) {
data[i] = i;
}
}
// 拷贝构造函数
Vector(const Vector& other) : size(other.size) {
data = new int[size];
for (size_t i = 0; i < size; ++i) {
data[i] = other.data[i];
}
}
// 移动构造函数
Vector(Vector&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
~Vector() {
delete[] data;
}
};
int main() {
Vector v1(1000000);
// 使用拷贝构造函数
auto startCopy = std::chrono::high_resolution_clock::now();
Vector v2 = v1;
auto endCopy = std::chrono::high_resolution_clock::now();
// 使用移动构造函数
auto startMove = std::chrono::high_resolution_clock::now();
Vector v3 = std::move(v1);
auto endMove = std::chrono::high_resolution_clock::now();
auto durationCopy = std::chrono::duration_cast<std::chrono::microseconds>(endCopy - startCopy).count();
auto durationMove = std::chrono::duration_cast<std::chrono::microseconds>(endMove - startMove).count();
std::cout << "Time taken by copy constructor: " << durationCopy << " microseconds" << std::endl;
std::cout << "Time taken by move constructor: " << durationMove << " microseconds" << std::endl;
return 0;
}
输出结果:
Time taken by copy constructor: 1651 microseconds
Time taken by move constructor: 0 microseconds
在上方的main函数中,首先创建了一个大型Vector对象v1,然后分别使用拷贝构造函数和移动构造函数创建了两个新对象v2和v3。使用了std::chrono库来测量拷贝和移动操作所需的时间。由于移动构造函数避免了数据的复制,所以它的执行时间远远少于拷贝构造函数。
输出结果显示,拷贝构造函数用时1651微秒,而移动构造函数几乎不需要时间(0微秒),展示了移动语义在处理大型对象时的性能优势。
文章来源:https://blog.csdn.net/qq_46348508/article/details/135178779
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!