智能指针与动态内存

发布于:2023-12-04 ⋅ 阅读:(105) ⋅ 点赞:(0)

动态内存

new

placement new 是 C++ 中的一种内存分配方式,它允许在给定的内存地址上构造对象,而不是在默认的堆上分配新的内存。这对于某些特殊的内存管理场景非常有用,例如在特定的内存池中分配对象。

C++11 引入了 "new auto" 语法,它允许你使用 auto 关键字来推断要分配的对象的类型。使用 "new auto" 的语法可以简化代码,特别是在创建复杂的类型或者使用模板时。

    // 使用 new auto 分配整数
    auto* myInt = new auto(42);

    // 使用 new auto 分配浮点数
    auto* myDouble = new auto(3.14);

alignas

是 C++11 引入的一个关键字,用于指定对齐方式。它可以用于变量、类型、结构体、类等,使得相应的对象或结构体成员按照指定的对齐方式进行对齐。

new会考虑struct的对齐信息

delete

不要delete非new返回的内存

智能指针

所有权不清晰 没销毁

解决方法:

share_ptr

常用接口

1. get 函数:

get 函数用于获取指向所管理对象的原始指针。这个原始指针可以用于调用不接受智能指针的函数或与 C 接口进行交互。需要注意的是,get 函数返回的是一个裸指针,它不负责引用计数,也不会影响 std::shared_ptr 的所有权。

    1. unique函数:判断该shared_ptr对象是否独占若独占,返回true。否则返回false。

    1. reset函数:
      • 当reset函数有参数时,改变此shared_ptr对象指向的内存。
      • 当reset函数无参数时,将此shared_ptr对象置空,也就是将对象内存的指针设置为nullptr。

new和share_ptr

智能指针构造函数是explicit的

指定内存回收逻辑

C++17和20支持的数组

new数组和delete不匹配现象

C++17和20解决方法

#include<iostream>
#include<memory>

int main(){
    std::shared_ptr<int>x(new int[5]);
    //delete(x.get())
    //C++17做法
    std::shared_ptr<int[]>x2(new int[5]);
    //C++20做法
    auto x3=std::shared_ptr<int[5]>();
    return 0;
}

unique_ptr

常用函数

    1. unque_ptr禁止复制构造函数,也禁止赋值运算符的重载。否则独占便毫无意义。、
    1. unqiue_ptr允许移动构造,移动赋值。移动语义代表之前的对象已经失去了意义,移动操作自然不影响独占的特性。
    1. reset函数:
      • 不带参数的情况下:释放智能指针的对象,并将智能指针置空。
      • 带参数的情况下:释放智能指针的对象,并将智能指针指向新的对象。

unique_ptr要传入del

weak_ptr和循环引用

x,y形成环 循环引用

智能指针实现原理

析构两次的解决方法

auto_ptr:管理权转移

template<class T>
	class auto_ptr {
	public:
		auto_ptr(T* ptr) :_ptr(ptr) {}
		auto_ptr(auto_ptr<T>& ap) :_ptr(ap._ptr) {
			ap._ptr = nullptr;
		}
 
		~auto_ptr()
		{
			if (_ptr) {
				cout << "delete:" << _ptr << endl;
				delete _ptr;
				_ptr = nullptr;
			}
 
 
		}
		T& operator*() {
			return *_ptr;
		}
		T* operator->() {
			return _ptr;
		}
	private:
		T* _ptr;
 
	};

缺陷:auto_ptr的问题:当对象拷贝或者赋值后,前面的对象就悬空了
 C++98中设计的auto_ptr问题是非常明显的,所以实际中很多公司明确规定了不能使用auto_ptr

unique_ptr:防拷贝

template<class T>
	class unique_ptr {
	public:
		unique_ptr(T* ptr) :_ptr(ptr) {}
		unique_ptr(unique_ptr<T>& ap) :_ptr(ap._ptr) {
			ap._ptr = nullptr;
		}
		unique_ptr<T>& operator=(unique_ptr<T>& up) = delete;
	
		~unique_ptr()
		{
			if (_ptr) {
				cout << "delete:" << _ptr << endl;
				delete _ptr;
				_ptr = nullptr;
			}
 
 
		}
		T& operator*() {
			return *_ptr;
		}
		T* operator->() {
			return _ptr;
		}
	private:
		T* _ptr;
 
	};

shared_ptr:引用计数

shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
 

template<class T>
	class shared_ptr {
	public:
		shared_ptr(T* ptr) :_ptr(ptr),_pcount(new int(1)) {}
		
		shared_ptr(shared_ptr<T>& sp) :_ptr(sp._ptr),_pcount(sp._pcount)
		{
			
			++(*_pcount);
		}
		shared_ptr<T>& operator=(shared_ptr<T>& sp) {
			if (this != &sp) {
				if (--(*_pcount) == 0) {
					delete _pcount;
					delete _ptr;
				}
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}
			return *this;
		}
 
		~shared_ptr()
		{
			if (--(*_pcount)==0&&_ptr) {
				cout << "delete:" << _ptr << endl;
				delete _ptr;
				_ptr = nullptr;
			}
 
 
		}
		T& operator*() {
			return *_ptr;
		}
		T* operator->() {
			return _ptr;
		}
	private:
		T* _ptr;
		int *_pcount;
	};