C++(2)----智能指针与动态内存

C++ 11提供的智能指针有:shared_ptr、unique_ptr、weak_ptr。在 头文件 memory 中。一、new delete 直接管理内存1、初始化string * ps = new string // 初始换为一个空string int * pi = new int ;//pi 指向一个...

C++ 11提供的智能指针有:shared_ptr、unique_ptr、weak_ptr。在 头文件 memory 中。

一、new delete 直接管理内存

1、初始化

string * ps = new string // 初始换为一个空string 
int * pi = new int ;//pi 指向一个未初始化的int,*pi 未定义

int * pi = new int(1024); // pi 指向的对象值为1024
string *ps = new string(10,'9') ; // *ps 为"9999999999"

vector<int> *pv = new vector<int>{0,1,2,3,4,5,6,7,8,9};

2、释放delete

int i, *pi1 = &i,  *pi2 = nullptr;
double *pd = new double(33),  *pd2 =pd;

delete i;  // 错误,, i不是一个动态分配的指针
delete pi1;  // 未定义错误,  pi1指向一个栈内存指针
delete pd;   //正确
delete pd2;  //未定义错误, pd2指向的内存已经被释放
delete pi2;   //正确:不能释放一个空指针

delete 之后应该重置指针, 

int *p(new int(42));
auto q =p;
delete p;
p=q=nullptr

 

3、使用new delete 管理内存常出现的问题

    没有delete内存,造成内存泄漏

    使用已经释放掉的对象

    同一块内存释放两次

 

二、shared_ptr:

  允许多个指针指向同一个对象。

定义与初始代码如下:

// 定义shared_ptr ,默认初始化为空指针
shared_ptr<string> p1;
shared_ptr<list<int>> p2;

// make_shared 函数, 头文件 memory
// 返回一个shared_ptr,  
// make_shared<T>(args)  使用args初始化对象
shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10,'9') // "9999999999"

shared_ptr<int> p5 = make_shared<int>(); //初始化为 0

和new 结合初始换

shared_ptr<int>p2(new int(42));

// 不能混淆普通指针和只能指针
shared_ptr<int> p1 = new int(1000);  // 错误
shared_ptr<int> p2(new int(1024));  // 正确


// 错误
shared_ptr<int> clone(int p) {
        return new int(p);      
}
// 正确
shared_ptr<int> clone(int p) {
        return shared_ptr<int>(new int(p));   
}

shared_ptr的拷贝和赋值、自动释放

引用计数; 当对象不再使用时,shared_ptr 会自动释放动态对象;

auto p = make_shared<int>(42); //p指向的对象只有p一个引用者
auto q(p);  // 递增一个引用计数

auto r = make_shared<int>(42);   //引用计数为1
r=q ;    //  给r赋值;  r原来指向的对象引用计数减1; q指向的对象引用计数+1; r原来指向的对象没有引用,自动释放

当引用计数为0是,内存会被释放,当普通指针  和智能指针混用是可能会出现错误。

// 一个函数,参数为 shared_ptr<int>
void process(shared_ptr<int> ptr) {A
      // 使用ptr
}// ptr离开作用于,销毁释放

/********   正确 ********/
shared_ptr<int> p(new int(42));   // 引用计数为1
process(p); // 参数作为值传递,在函数内部引用计数为2,之后为1
int i = *p; //内有问题, 引用计数值为1;

/*********  错误 ********/
int *x(new int(1024));   // 这是一个普通的指针
process(x) ; // 错误,普通指针不能转换为 shared_ptr<int>
porcess(shared_ptr<int>(x)); //合法,但是危险,函数结束后,会释放内存
int j =*x ; // 错误,此时内存已经被释放 

谨慎的使用get() 函数,只有保证内存不被释放的前提现使用。

不能用get 初始化另一个智能指针,或为另一个智能指针赋值

// 谨慎使用 get() 函数

shared_ptr<int> p(new int(42));  // 引用计数为1
int * q = p.get(); // 合法,但是保证内存释放的时机

{// 程序块
  // 不要使用get() 对另一个智能指针初始化,这样对同一块内存,有多个计数
  shared_ptr<int>(q);
}// q被销毁释放
int foo = *p; // 此时p所指向的内存已经被释放

在发生异常时,智能指针也能保证内存被释放

// 使用 new 分配内存,应当注意由于分支  和 异常造成的内存泄漏
void f()
{
      int *ip = new int(42);  // new 动态分配
      // 发生异常
      delete ip;    // 之前发生异常,这里可能造成内存泄漏   
} 


// 使用智能指针, 在发生异常时,内存也会被释放
void f()
{
     shared_ptr<int> sp (new int(42)); // 分配一个新对象
     // 发生异常
    
}//  在函数结束时,shared_ptr 被销毁,同时释放指向的内存

 资源管理《c++primer》:

 

 

三、unique_ptr:

独占,同一时间只有一个智能指针可以指向这个对象。

不支持普通的拷贝,和赋值

unique_ptr<string> p3 (new string ("auto"));    //#4
unique_ptr<string> p4;                         //#5
p4 = p3;                                     //   出错
unique_ptr<string> p4(p3); //出错:不支持拷贝

unique_ptr<string> p2(p1.release()) // release 将p1置为空
unique_ptr<string> p3(new string("Trex"));
// 将所有权从p3转移给p2
p2.reset(p3.release());

 

四、weak_ptr

 不控制所指向对象生存期。

指向由一个shared_ptr管理的对象(由shared_ptr管理生命周期)

将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数

// 初始化
auto p = make_shared<int>(42);
weak_ptr<int> wp(p);   // 若共享,p的技术不变

// 生命周期由shared_ptr 管理,因此weak_ptr指向的对象可能为空
// 可使用lock 检查是否为空
// lock 返回一个指向共享对象的shared_ptr
if(shared_ptr<int> np = wp.lock())
{
.......
}

 五、智能指针与动态数组

int *pia = new int[10];   // 10个未初始化的int
int *pia2 = new int[10]();  //10个值初始化为0的int
string *psa = new string[10]; //10个空string
string *psa2 = new string[10](); // 10个空string

int * pia3 = new int[3]{0,1,2};

delete [] pia;


unique_ptr<int[]> up(new int[10]);
up.release(); //自动使用delete[] 销毁指针

 

// allocator  在头文件memory 中
//  将内存分配和对象构造分离
//  分配原始 未构造
// 是一个模板

allocator<string> alloc;  //可以分配string的allocator 对象
auto const p = alloc.allocate(n);   //分配n个未初始化的string

 

参考:

https://blog.csdn.net/k346k346/article/details/81478223

https://www.cnblogs.com/WindSun/p/11444429.html

《c++ primer》第12章

https://www.cnblogs.com/KunLunSu/p/7861330.html

本文标题为:C++(2)----智能指针与动态内存

基础教程推荐