1. 前言
本次介绍c++特殊函数是指C++中类的成员和类对象的操作函数。其中包含五个重要的特殊函数:构造函数、拷贝构造函数、拷贝赋值函数,移动构造函数、移动赋值函数,析构函数。
本文主要针对有一定c++基础的同学,大部分都是样例测试,不会有太多的文字解释和说明。接下来分别介绍这六个函数的作用和调用时机。
2、函数介绍
2.1 基础测试代码
下面一个简单类实现了六个特殊函数,内部只是一个简单的打印,来测试调用时机添加的。
class TestConstruct {
public:
TestConstruct()
{
cout << "this is TestConstruct()" << endl;
}
~TestConstruct()
{
cout << "this is ~TestConstruct()" << endl;
}
TestConstruct(const TestConstruct& test)
{
cout << "this is copy TestConstruct()" << endl;
}
TestConstruct& operator=(const TestConstruct& test)
{
cout << "this is operator= TestConstruct()" << endl;
return *this;
}
TestConstruct(const TestConstruct&& test)
{
cout << "this is move copy TestConstruct" << endl;
}
TestConstruct& operator=(TestConstruct&& test)
{
cout << "this is move = TestConstruct" << endl;
return *this;
}
};
2.2拷贝构造函数
定义:如果构造函数的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,则该构造函数时拷贝构造函数。如果没有为类定义拷贝构造函数,则编译器会默认生成拷贝构造函数。
用途:定义已存在的类对象,去初始化该类的新对象的成员初始化过程。
// 调用时机
TestConstruct test1; // 无参构造
TestConstruct test2(test1); // 拷贝构造
TestConstruct test3 = test1; // 拷贝构造
2.3 拷贝赋值运算符
定义:重载类对象赋值操作符“=”的函数,就是拷贝赋值运算符。简单的说就是重载运算符函数。
// 调用时机
TestConstruct test4;
test4 = test1; // 拷贝赋值函数
2.4 移动构造函数、移动赋值运算符
简单的来说就是将一个原先对象的管理权移动到另一个新对象上。原先被对象则不可再用,因为管理权已移动到新的对象上!!!移动构造函数和移动赋值运算符的优点是不用深拷贝数据,直接将原先的对象数据移动到新的对象上,提高了效率。
// 调用时机
TestConstruct test1; // 无参构造
TestConstruct test4(std::move(test1)); // 移动拷贝构造
TestConstruct test5;
test5 = std::move(test1); // 移动赋值构造
2.5 性能剖析
我们知道拷贝构造 拷贝赋值的性能是低于 移动构造和移动赋值的。
通过一个代码实例以及调用一万次拷贝构造和移动拷贝构造测试时间上的差异性。
// 成员变量就一个简单int指针
class TestConstruct {
private:
int* ptr = nullptr;
public:
TestConstruct()
{
ptr = new int(10);
}
~TestConstruct()
{
if (ptr != nullptr) {
delete ptr;
ptr = nullptr;
}
}
TestConstruct(const TestConstruct& test)
{
if (ptr != nullptr) {
delete ptr;
ptr = nullptr;
}
this->ptr = new int(*test.ptr); // 重新开辟空间 耗时
}
TestConstruct& operator=(const TestConstruct& test)
{
if (ptr != nullptr) {
delete ptr;
ptr = nullptr;
}
this->ptr = new int(*test.ptr); // 重新开辟空间 耗时
return *this;
}
TestConstruct(TestConstruct&& test)
{
if (ptr != nullptr) {
delete ptr;
ptr = nullptr;
}
this->ptr = test.ptr; // 地址转移,无需重新new空间
test.ptr = nullptr;
}
TestConstruct& operator=(TestConstruct&& test)
{
if (ptr != nullptr) {
delete ptr;
ptr = nullptr;
}
this->ptr = test.ptr; // 地址转移,无需重新new空间
test.ptr = nullptr;
return *this;
}
};
// 性能测试
void func1()
{
int i = 0;
while (i < 1000000) {
TestConstruct a1;
TestConstruct a2 = a1;
i++;
}
}
void func2()
{
int i = 0;
while (i < 1000000) {
TestConstruct a1;
TestConstruct a2 = std::move(a1);
i++;
}
}
int main() {
int t1 = clock();
func1();
int t2 = clock();
func2();
int t3 = clock();
cout << (t2 - t1) << " " << (t3 - t2) << endl; // 323ms 200ms
return 0;
}
由上测试性能差距还是很大的。