[C++复习]:异常/智能指针/类型转换/IO流
异常
try {
// 可能出错的代码
if (出错)
throw 异常对象;
}
catch (异常类型1 e) {
// 处理
}
catch (const exception& e) {
// 处理
cout << e.what() << endl;
}
catch (...)
{
cout << "未知异常" << endl;
}
异常的优缺点
- 优点
展示错误更清晰
错误码调用太深,异常直接处理
第三方库也有异常
有些没有返回值(void)的函数使用异常更方便 - 缺点
执行流乱跳:
正常流程、异常流程分开,代码逻辑不线性,难维护。
容易内存泄漏:
抛出异常时函数直接退出,new 的内存没 delete、锁没释放。
→ 解决:RAII(智能指针、lock_guard 等)。
异常体系混乱复杂度很高。
C++ 异常安全等级
基本保证:不崩、不漏、状态合法就行。
强保证:要么成功,要么回滚,无中间态。
不抛保证:noexcept,绝对不抛异常。
怎么实现强异常安全?
Copy & Swap。先拷贝一份做修改,成功后再用不抛异常的 swap 替换原对象。
智能指针
什么是智能指针
用对象管理指针,利用 RAII 机制自动释放资源。
不用手动 delete,杜绝内存泄漏。
RAII
资源获得即初始化
(在构造函数申请资源,在析构函数释放资源)
利用对象生命周期管理资源,由编译器自动调用析构
智能指针原理
把原始指针封装成类对象
重载 *、-> 让它用起来像指针
出作用域 → 自动调用析构 → 自动释放内存
四种智能指针
std::auto_ptr
废弃,不要用!
拷贝时会把所有权偷走,原指针置空
std::unique_ptr
独占式智能指针
同一时间只有一个指针管理对象
不能拷贝,只能移动
unique_ptr<int> p1(new int(10));
// 不能拷贝!编译报错
// unique_ptr<int> p2 = p1;
// 可以移动所有权
unique_ptr<int> p2 = move(p1);
// 现在 p1 为空,p2 拥有对象
if (p1 == nullptr) {
cout << "p1 为空" << endl;
}
效率最高,无额外开销
std::shared_ptr
共享式智能指针
引用计数实现
多个指针指向同一个对象
计数为 0 才释放内存
有性能开销(原子操作)
shared_ptr<int> p1(new int(10));
cout << p1.use_count() << endl; // 1
shared_ptr<int> p2 = p1; // 拷贝,计数+1
cout << p1.use_count() << endl; // 2
p1.reset(); // 主动释放,计数-1
cout << p2.use_count() << endl; // 1
std::weak_ptr
弱引用指针
辅助 shared_ptr
不增加引用计数
专门解决 循环引用
wp.lock(); // 返回一个 shared_ptr,若对象已死则为空
wp.expired(); // 判断对象是否已销毁
shared_ptr<int> sp = make_shared<int>(10);
weak_ptr<int> wp = sp;
cout << sp.use_count() << endl; // 1,weak_ptr 不增加计数
if (!wp.expired()) {
shared_ptr<int> temp = wp.lock();
// 使用对象
}
缺陷
循环引用
(shared_ptr 致命问题)
A->B B->A
互相持有 shared_ptr
计数永远 >=1 → 内存泄漏!
解决:一方使用 weak_ptr
性能开销
引用计数是原子操作(线程安全)
频繁构造销毁++有开销
shared_ptr手撕
template <typename T>
class SharedPtr {
public:
// 构造
SharedPtr(T* ptr = nullptr)
: _ptr(ptr), _count(new int(1)) {}
// 拷贝构造
SharedPtr(const SharedPtr& other) {
_ptr = other._ptr;
_count = other._count;
(*_count)++; // 计数++
}
// 赋值重载(重点!必须先释放自己)
SharedPtr& operator=(const SharedPtr& other) {
if (this == &other) return *this;
// 释放当前对象
release();
// 共享资源
_ptr = other._ptr;
_count = other._count;
(*_count)++; // 计数++
return *this;
}
// 析构
~SharedPtr() {
release();
}
// 重载 * ->
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
int useCount() { return *_count; }
private:
void release() {
if (_ptr == nullptr) return;
(*_count)--;
if (*_count == 0) {
delete _ptr;
delete _count;
_ptr = nullptr;
_count = nullptr;
}
}
T* _ptr;
int* _count; // 引用计数
};
赋值后要记得更新计数
定制删除器
默认智能指针用 delete 释放资源,定制删除器就是让你自己写 “怎么释放”。
适用场景:
不是 new 出来的内存(malloc / mmap)
文件指针 FILE*
套接字 socket
数据库连接
自定义清理逻辑
//关闭文件
shared_ptr<FILE> sp(fopen("test.txt", "w"), [](FILE* pf) {
cout << "fclose 文件" << endl;
fclose(pf);
});
// free 释放 malloc 内存
shared_ptr<void> sp(malloc(100), [](void* p) {
free(p);
//函数指针当删除器
void my_delete(int* p) {
cout << "自定义删除\n";
delete p;
}
int main() {
shared_ptr<int> sp(new int, my_delete);
}
});
//数组可以直接用[]
shared_ptr<int[]> sp(new int[10]);
类型转换
static_cast
编译期转换,用于隐式类型转换,可以显示替换
没有类型检查,不安全
// 1. 基本类型
int a = 10;
double b = static_cast<double>(a);
// 2. 基类 ↔ 派生类(无运行时检查,不安全!)
Base* base = new Derived;
dynamic_cast
运行期检查,用于基类到派生类转换
基类转到派生类失败会返回nullptr
必须要有虚函数!
Base* base = new Derived;
// 基类 转 派生类
Derived* der = dynamic_cast<Derived*>(base);
if (der != nullptr) {
// 转换成功
} else {
// 转换失败
}
const_cast
用于去除或增加const性质
const int a = 10;
// 去掉 const
int* p = const_cast<int*>(&a);
*p = 20;
reinterpret_cast
无关类型指针互转
极其危险,相当于暴力强制转换
底层对数据进行重新解释,危险
int a = 10;
// 把 int 指针 强转成 char 指针
char* pc = reinterpret_cast<char*>(&a);
IO流
库的意义:
1、面向对象
istream / ostream / iostream 都是类
cin、cout 是全局对象
2、支持自定义类型流插入和提取
最常用的 4 个对象
cin 输入(键盘)
cout 输出(屏幕)
cerr 错误输出(无缓冲)
clog 日志输出
三大文件流类
ifstream 读文件
ofstream 写文件
fstream 读写文件(有缓冲)
#include <fstream>
// 写
ofstream ofs("test.txt");
ofs << "hello";
// 读
ifstream ifs("test.txt");
string s;
ifs >> s;
字符串流 stringstream
作用:字符串与数字互转、字符串分割、拼接
- 数字 → 字符串
int a = 123;
stringstream ss;
ss << a;
string s = ss.str();
- 字符串 → 数字
string s = "123";
stringstream ss(s);
int a;
ss >> a;
自定义类型重载 <<
operator<<(cout, obj);
class Person{
friend ostream& operator<<(ostream& out,const Person&p);
private:
int age=10;
};
ostream& operator<<(ostream&out,const Person&p){
out<<p.age;
return out;
}
Preson p;
cout<<p<<endl;
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)