C++之小白看内存申请与释放

734 阅读3分钟

C++ 的内存分配方式和c有区别,c采用的是malloc realloc calloc 等方式,c++采用new和delete

首先要明白堆栈的概念

全局区,静态区:static

常量区: ""

堆:new,【需要自己主动释放】

栈:局部变量,【最大空间以系统为准,一般2M,超过会抛Stack Overflow的错误】

c++中声明对象的方式有如下几种

T t;
T t();
T* t= new T(); //new 会在堆开辟一个空间

实例:

#include <iostream>

class T {
public :
    T(){
        std::cout<<"构造函数"<<count<<std::endl;
    }
    ~T(){
        std::cout<<"析构函数"<<count<<std::endl;
    }
    T(const T& t){
        std::cout<< "拷贝构造函数"<<count<<std::endl;
    }

    T& operator= (const T &t){
        std::cout<< "赋值操作符"<<count<<std::endl;
    }
    void countPP(){
        count ++;
    }
    void printData(){
        std::cout<< "我是打印"<<count<<std::endl;
    }
private:
    int count =0;

};

void fun(T * t){
    t->countPP();
    t->printData();
    std::cout<<"执行完毕"<<std::endl;
}

int main(int argc, char *argv[])
{
    T t ; //栈上,不需要自己释放
    fun(&t);

    std::cout<<"执行第二种申请方式"<<std::endl;

    T* tp = new T();//在堆上,需要自己释放
    fun(tp);
    delete tp;
    tp= NULL; // 需要指向NULL,否则有可能误触不可访问的内存地址
}

输出

构造函数0
我是打印1
执行完毕
执行第二种申请方式
构造函数0
我是打印1
执行完毕
析构函数1 【这个是指针的释放,由我们调用delete触发】
析构函数1 【方法退出,由系统自动调用析构】

由上面可以看出在调用完毕相应的方法之后,需要主动释放。

所有的程序都是由简到繁,所以注重释放的时机很重要

原则上,谁申请谁消费的原则。

这里再举一个例子,来说明你是否明白了堆栈的概念。【可能会有点绕】

//KTmpCommSession.h
class KTmpCommSession
{
public:
    KTmpCommSession();
    static uint32_t& get_session_id();
};
//KTmpCommSession.cpp
KTmpCommSession::KTmpCommSession()
{
}
static uint32_t session_id = 0;

uint32_t &KTmpCommSession::get_session_id()
{
 return session_id;
}

//ktmp.h
template <typename  T>
class KTmp:public KTmpCommSession
{
public:
    KTmp(){autoIncreateSessionId();}
public:
    T* callback = nullptr;
    int getSessionId()
    {
        return get_session_id();
    }
private:
    void autoIncreateSessionId()
    {
        ++get_session_id();
        if(get_session_id() == 0)
        {
            get_session_id() = 1;
        }
    }
};

首先定义了一个模板类,细心的同学是不是发现为什么要对一个模板类进行继承,原因:是因为我想我的所有模板都有一个共有的属性,而这个属性每次在构造的时候都会被累加。每构造一个不同的模板子类都会触发这个属性变化。故有了上面的写法。为什么不写在同一个类里面,因为打包的时候可能会因为在不同的so中导致,有bug。

//init.cpp
#include <functional>
typedef std::function<void* (void *)> TEST;

void KInit::active(TEST fun)
{
    KTmp<TEST> *args = new KTmp<TEST>();
    args->callback = new TEST(fun);//【1】这里注意
    async_request(args);//异步发起请求,涉及异步【2】这里注意
}
//args 这个参数是async_request传递过来的参数,这个方法会被async_request调用,async_request的具体实现,这里先不给出,
static void _result_init(void *args){
    KTmp<TEST> * param = (KTmp<TEST> *)args;
    if(args!=NULL){
        TEST * t = param->callback;
        (*t)((void*)(""));  //【3】这里注意
        std::cout<<":::::::void::::"<<t<<std::endl;
    }
}

//main.cpp
void * xxx(void * data){
    std::cout<<"init init init:"<<std::endl;
}

int main(int argc, char *argv[])
{
    KInit init;
    init.active(xxx);
}

注意上面标注的【1】【2】【3】

如果【1】没有new的话,那么在【3】就会抛异常,原因就是因为【2】是异步导致被释放了。

参考资料:

The stack and the heap

C++--堆和栈详解