1.默认成员函数
C++ 类会自动生成6 大默认成员函数,C++11 用 =default / =delete 精准控制这些函数。
1.默认构造函数
2.析构函数
3.拷贝构造函数
4.拷贝赋值运算符
5.移动构造函数(C++11)
6.移动赋值运算符(C++11)
| 关键字 | 作用 | 典型场景 |
|---|---|---|
=default | 让编译器生成默认实现 | 手动写构造后,恢复默认构造 |
=delete | 显式禁用该函数 | 禁止类被拷贝(单例模式) |
代码示例:
#include <iostream> using namespace std; class Test { public: // 1. 强制生成默认构造函数 Test() = default; // 2. 禁用拷贝(核心:单例模式必用) Test(const Test&) = delete; Test& operator=(const Test&) = delete; // 3. 强制生成默认移动函数 Test(Test&&) = default; Test& operator=(Test&&) = default; }; int main() { Test t1; // Test t2(t1); 报错:拷贝被禁用 Test t3(std::move(t1)); // 正常:移动可用 return 0; }1.移动构造函数
核心定义:
作用:用一个右值(临时对象)初始化新对象时调用
语法:类名(类名&& 源对象) noexcept;
&&:右值引用,专门绑定临时对象
noexcept:告诉编译器无异常(STL 容器强制要求)
核心逻辑:接管资源 → 把源对象的指针 / 内存拿过来,源对象置空
2. 手写实战(最能理解原理)
我们写一个带动态内存的 String 类,对比拷贝构造和移动构造:
#include <iostream> #include <cstring> using namespace std; class String { private: char* _str; // 动态内存,深拷贝核心 public: // 构造函数 String(const char* str = "") { _str = new char[strlen(str) + 1]; strcpy(_str, str); cout << "构造函数: " << _str << endl; } // 1. 拷贝构造函数(深拷贝:复制一份) String(const String& s) { _str = new char[strlen(s._str) + 1]; strcpy(_str, s._str); cout << "拷贝构造(深拷贝): 复制 -> " << _str << endl; } // 2. 移动构造函数(核心!转移资源,不拷贝) String(String&& s) noexcept { _str = s._str; // 直接接管临时对象的内存 s._str = nullptr; // 源对象置空!防止析构时释放资源 cout << "移动构造(转移资源): 接管 -> " << _str << endl; } // 析构函数 ~String() { if (_str) { delete[] _str; cout << "析构函数" << endl; } } // 打印 const char* c_str() const { return _str; } }; // 测试函数:返回临时对象(右值) String getTempString() { return String("临时对象"); } int main() { // 调用移动构造:用临时对象初始化新对象 String s1 = getTempString(); cout << "s1内容: " << s1.c_str() << endl; return 0; }运行结果:
✅ 没有执行拷贝构造,直接转移资源,性能拉满!
2、移动赋值运算符
核心定义:
作用:用一个右值给已经存在的对象赋值时调用
语法:类名& operator=(类名&& 源对象) noexcept;
核心逻辑:
1.释放自己当前的资源
2.接管源对象的资源
3.源对象置空
4.返回自身引用
手写实战(接上 String 类)
在上面的类中添加移动赋值运算符:
// 3. 拷贝赋值运算符(深拷贝) String& operator=(const String& s) { if (this == &s) return *this; // 防止自赋值 delete[] _str; // 释放旧资源 _str = new char[strlen(s._str) + 1]; strcpy(_str, s._str); cout << "拷贝赋值(深拷贝)" << endl; return *this; } // 4. 移动赋值运算符(核心!转移资源) String& operator=(String&& s) noexcept { if (this == &s) return *this; // 1. 防止自赋值 delete[] _str; // 2. 释放当前对象的旧资源 _str = s._str; // 3. 接管临时对象资源 s._str = nullptr; // 4. 源对象置空 cout << "移动赋值(转移资源)" << endl; return *this; }测试移动赋值:
int main() { String s2("已存在的对象"); // 调用移动赋值:临时对象赋值给已存在对象 s2 = getTempString(); cout << "s2内容: " << s2.c_str() << endl; return 0; }运行结果:
2.右值引用
C++11性能优化核心,解决临时对象拷贝浪费资源的问题。
1. 基础概念
左值:有名字、能取地址、持久存在(如变量int a=10);
右值:临时对象、不能取地址、用完即销毁(如10、函数返回的临时值);
右值引用:&&,专门绑定右值,实现移动语义。
2. 核心作用:移动语义
不拷贝数据,直接接管临时对象的资源(比如字符串的字符数组、容器的内存),性能提升巨大。
3. 关键:std::move ()
将左值强制转为右值引用,触发移动操作。
代码示例:
#include <iostream> #include <string> using namespace std; int main() { string s1 = "hello world"; string s2 = std::move(s1); // 移动:s1把内存交给s2,无拷贝 cout << "s2: " << s2 << endl; // hello world cout << "s1: " << s1 << endl; // 空(资源被移走) return 0; }扩展:完美转发
std::forward<T>():保留参数的左 / 右值属性,用于通用模板函数,避免类型丢失。