我的c++学习之旅 cpp-learning-journey day03

Day03

  • 今天补了一下前两天落下的,更新了一下day01 02

智能指针

  • 智能指针是为了帮助解决动态内存分配的,它会帮助我们管理我们new出来的空间,避免内存泄漏
  • 智能指针通过RAII(资源获取即初始化)机制解决这个问题:对象生命周期结束时自动释放资源
  • 智能指针头文件:memory
  • 智能指针分类:
std::unique_ptr
std::shared_ptr
std::weak_ptr
std::auto_ptr//c++11已经废用,这里不讨论
  • std::unique_ptr:独占所有权指针,同一时刻只能有一个std::unique_ptr指向目标内存
int main() {
	std::unique_ptr<int>p1(new int(50));//p1指向有50个元素的int数组
	*p1 = 100;//数组首元素赋值100
	std::cout << *p1 << std::endl;//输出100
	//p1离开作用域自动释放内存,无需手动delete
	std::unique_ptr<int>p2 = std::make_unique<int>(50);//c++14 更推荐的创建用法
	return 0;
}
  • std::unique_ptr独占所有权但是可以移动
std::unique_ptr<int> p3 = std::move(p1);  // p1 变为空
  • shared_ptr:共享所有权指针,支持多个shared_ptr指向同一目标内存
  • 实际上我们可能需要多个指针同时指向同一内存,使用std::unique_ptr无法完成,所以我们需要shared_ptr
  • 工作机理:shared_ptr有一个计数器,每次指向这片内存的shared_ptr多一个,计数器就加一,只有计数器归的时候才会回收内存
class Resource {
public:
	Resource() {
		std::cout << "Resource acquired\n";
	}
	~Resource() {
		std::cout << "Resource destroyed\n";
	}
	void use() {
		std::cout << "Using resource\n";
	}
};

void shared_ptr_demo() {
	// 创建shared_ptr(推荐make_shared)
	std::shared_ptr<Resource> s1 = std::make_shared<Resource>();

	{
		// 共享所有权
		std::shared_ptr<Resource> s2 = s1;
		std::cout << "Use count: " << s1.use_count() << std::endl; // 2

		s2->use();
	} // s2析构,引用计数减1

	std::cout << "Use count: " << s1.use_count() << std::endl; // 1

	// 自定义删除器
	std::shared_ptr<Resource> s3(
	    new Resource(),
	[](Resource * res) {
		std::cout << "Custom deleter called\n";
		delete res;
	}
	);

	// 数组支持(C++17)
	std::shared_ptr<Resource[]> arr(new Resource[3]);//s4 s5 s6
} // 资源自动释放

int main() {
	shared_ptr_demo();
}
  • 最终输出
Use count: 2//s1 s2两个
Using resource//s2->use
Use count: 1//s1 一个
Resource acquired//s3
Resource acquired//s4
Resource acquired//s5
Resource acquired//s6
Resource destroyed//s6
Resource destroyed//s5
Resource destroyed//s4
Custom deleter called//s3
Resource destroyed//s3
Resource destroyed//s1

-常见错误

int* raw = new int(42);
std::shared_ptr<int> p1(raw);
std::shared_ptr<int> p2(raw); // 双重释放!
//正确写法
std::shared_ptr<int> p1 = std::make_shared<int>(42);
auto p2 = p1; // 共享所有权
  • 函数传递
// 正确传递方式:
void process_resource(std::shared_ptr<Resource> res); // 共享所有权

void use_resource(const Resource& res);               // 只读访问
void modify_resource(Resource* res);                 // 写访问(需确保生命周期)
  • std::weak_ptr:观察但是不拥有资源(不会增加std::shared_ptr的计数),核心用途是为了打破循环应用,一般和shared_ptr使用
  • 循环引用问题
class B; // 前向声明

class A {
public:
    std::shared_ptr<B> b_ptr;
    ~A() { std::cout << "A destroyed\n"; }
};

class B {
public:
    std::shared_ptr<A> a_ptr;
    ~B() { std::cout << "B destroyed\n"; }
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->b_ptr = b;
    b->a_ptr = a;

    // main 结束后,a 和 b 的引用计数都 > 0,无法释放
}
  • 使用std::weak_ptr解决
class B; // 前向声明

class A {
public:
	std::shared_ptr<B> b_ptr;
	~A() {
		std::cout << "A destroyed\n";
	}
};

class B {
public:
	std::weak_ptr<A> a_ptr;
	~B() {
		std::cout << "B destroyed\n";
	}
};

int main() {
	std::shared_ptr<A> a = std::make_shared<A>();
	std::shared_ptr<B> b = std::make_shared<B>();

	a->b_ptr = b;
	b->a_ptr = a;

	//可以正常释放
}
  • 智能指针的底层

    • shared_ptr控制块结构
    struct ControlBlock {
    long shared_count;   // 强引用计数
    long weak_count;     // 弱引用计数
    Deleter deleter;     // 自定义删除器
    Allocator allocator; // 分配器
    // 指向管理对象的指针
    };
    
    • new和make_shared的区别
    特性make_shared直接使用new
    内存分配单次分配(对象+控制块)两次分配(对象+控制块)
    异常安全可能泄漏
    缓存友好是(局部性原理)
    弱引用延迟释放控制块和对象一起释放对象可单独释放
  • 更多用法

    • 自定义删除器
    auto my_delete = [](Test* t){
        //你自己的删除逻辑
        delete t;
    };
    std::shared_ptr<Test>Test_ptr(new Test(),my_delete);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值