5.2c++:new、delete探秘,智能指针概述,shared_ptr基础部分、make_shared函数

 

一、new / delete探秘

1、new,delete是什么

sizeof关键字,不是一个函数。

new,delete关键字,不是函数。

malloc,free主要用于C语言,而new,delete用于C++编程,这两对都用于动态的在堆中分配和释放内存。

new,delete会调用类的构造与析构函数,malloc与free比new和delete更底层。new / delete具备对 堆上所分配内存进行初始化 / 释放 的能力,而这些能力是 malloc/free所不具备的。

#include <iostream>
#include <vector>
using namespace std;

class A
{
    public:
    A()
    {
        cout <<"A构造"<<endl;
    }
    ~A()
    {
        cout <<"A的析构函数" << endl;
    }
};
int main()
{
    A *pa = new A();//构造函数被调用了
    delete pa;      //会调用析构函数

    return 0;
}

2、operator new() 和 operator delete()函数:

    int *pi =new int;
    delete pi;

new干了两个事情:a、分配内存(通过operator new()来分配内存) b、调用构造函数来初始化内存

void *mypoint = operator new(100); //这种写法虽然不报错,但是很不常见

delete也干了两个事:a、调用析构函数  b、释放内存(调用 operator delete()来释放内存)
 

基本new如何记录分配的内存大小工delete使用


不同的编译器new内部有不同的使用方法

int *p = new int; //4个字节

delete p; //删除的时候,编译器怎么知道要回收的是4个字节:new内部有记录机制

 

#include <iostream>
#include <vector>
using namespace std;

class A
{
    public:
    A()
    {
        cout <<"A构造"<<endl;
    }
    ~A()
    {
        cout <<"A的析构函数" << endl;
    }

};
int main()
{
     return 0;
}

main:

​
    申请和释放一个组
    int *p1 = new int(100); 分配4个字节,给int = 100;
    int *p2 = new int [2] ; int数组,有两个元素,如果没delete泄露8个字节
    delete p1;
    delete []p2;
    A a;
    int ilen = sizeof(a) ;类对象肯定有地址,至少占一个字节的地址。‘
    cout << ilen << endl;  结果为1

    有构造函数和析构函数也是占一个字节。因为构造函数和析构函数(成员函数)不占用类对象的内存
   
    加一个成员变量大小就会变成4   如:  int m_b;
A *pa = new A();      泄露一个字节
A *pa2 = new A[2]();  泄露6个字节,而不是2个字节。多出了4个字节
int *p = new int[2] ; int 数组有两个字节,泄露8个字节,没有多出4个字节

疑问:为什么动态给类项A分配内存对象数组的时候多出4个字节,而内置类型int动态分配内存对象时没有多出4个字节?

    int *p2 = new int [2] ; int数组,有两个元素,如果没delete泄露8个字节
    delete p2;使用这个来释放也可以,系统没报错
    delete []p2; 合规是使用这种析构的方法。
A *pa2 = new A[2]();  泄露6个字节,而不是2个字节。多出了4个字节


这种对类对象数组使用 delete pa2;系统就会报错。
必须使用             delete [] pa2;

现在把类A的析构函数删掉:

A *pa2 = new A[2]();  现在泄露2个字节了


这种对类对象数组使用 delete pa2;系统不会报错。
也可以使用           delete [] pa2;
所以:多出来的4个字节,就是记录有几个A对象,来构造几次,释放几次。
保存数组的大小内置类型int数组,不需要析构函数。同理,如果一个类,无自定义的析构函数,也可以不用写[]

一定要配对使用,不配对使用,会出很对问题。 如果是mew A(); 然后 delete[] ,这样也会出错。
出错的主要原因,就是那4个字节的空间。

智能指针总述

智能指针:理解成对“裸指针”进行包装,给裸指针外边包了一层;包装后带来优点

最突出的优点:智能指针 能够“自动释放所指向的对象内存” 

有四种智能指针:
auto_ptr(c++98) 
c++11: unique_ptr shared_ptr weak_ptr

c++11反对使用auto_ptr ,这个不好用

shared_ptr 是共享式指针。多个指针指向同一个对象,最后一个指针被销毁时,这个对象释放
   
weak_ptr 是辅助shared_ptr工作的
     
unique_ptr :独占式指针,同一个时间内,只有一个指针能够指向该对象,当然,该对象的所有权还是可以移交出去的。
      


忘记delete的时候,智能指针 帮助你delete
     

 

shared_ptr基础

共享所有权,不是被一个shared_ptr拥有,而是被多个shared_ptr之间相互协作
    有额外的开销
    工作原理:引用计数,每个shared_ptr的拷贝都指向相同的内存,
    所以,只有最后一个指向该内存的shared_ptr指针不需要再指向该对象时,就会析构。

释放的时机:a)这个shared_ptr被析构的时候 b)这个shared_ptr指向其他的对象时。

类模板,用到<>  <>里,就是指针可以指向的类型,后边再跟智能指针名。
格式:shared_ptr<指向的类型名> 智能指针名;
      shared_ptr<int> pitr; 
      指向int的智能指针,名字为pitr,但是目前为空,空指针,nullptr 

常规的初始化:new 和 shared_ptr进行配合

shared_ptr <int> pi (new int(100)); 这是对的
shared_ptr <int> pi2 =new int (100); //不进行隐式类型转换,这种就是错误的
shared_ptr<int> newABlock(int value)
{
   错误,无法把new得到的int*转换成shared_ptr
   // return new int(vlaue);
   
   return shared_ptr <int> (new int(value));
}
 裸指针可以初始化shared_ptr,但不推荐,智能指针和裸指针不要穿插使用。
    int *pi2 = new int;
    shared_ptr <int> p1 (pi2);不推荐,容易出问题

make_shared函数

 标准库里的函数模板,安全高效的分配和使用shared_ptr。

它能够在动态内存(堆)中,分配并初始化一个对象,然后返回指针指向对象的shared_ptr

#include <iostream>
#include <vector>
#include <memory> // shared_ptr
using namespace std;


int main()
{
    shared_ptr <int> p = make_shared<int> (100);
    //这个shared_ptr指向一个值为100的整型内存,有点类似于int *p = new int(100);
   shared_ptr <string> pstr = make_shared<string> (5,'a');
   //5个字符a生成的字符串 类似于string pstr (5,'a');

   shared_ptr<int> p2 = make_shared<int> ();//p2指向一个int,int里面保存的值是0
   p2 = make_shared<int> (100);//p2指向一个新int,int里保存的是100.
   //p2首先释放刚才指向的值为0 的内存,然后指向新的分配的内存。


   auto p5 = make_shared<int> (100);//使用auto更加方便。
   //make_shared<> 也有一定的局限性,没有办法自定义删除器,以后会讲的。

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值