C++ 内存管理 基本部分

内存管理

基本体

分配内存和释放内存

方式

分配释放类别能否重载
malloc()free()c函数不可
newdeletec++表达式不可
::operator new()::operator delete()c++函数
allocator::allocate()allocator::deallocate()c++标准库可自由设计并且搭配任何容器

示例

#include <complex>
#include <stdlib.h>
using namespace std;
int main()
{
    char *p = (char *)malloc(512);
    p[0] = 'c';
    free(p);

    complex<int> *p2 = new complex<int>;
    delete p2;

    void *p3 = ::operator new(512);
    ::operator delete(p3);

#ifdef __GNUC__
    void *p5 = allocator<int>().allocate(7);
    allocator<int>().deallocate((int *)p5,7);
#endif
    return 0;
}

new 和 delete

不能直接调用构造函数,但是可以直接调用析构函数

#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

class MemoryTest
{
public:
    MemoryTest()
    {
        cout << "MemoryTest"<< endl;
    }
    ~MemoryTest()
    {
        cout << "~MemoryTest"<< endl;
    }
};

int main()
{
    // MemoryTest *str = new MemoryTest();
    // str->MemoryTest();
    MemoryTest str2;
    // str->~MemoryTest();
    str2.~MemoryTest();
    return 0;
}

如果类内有指针则会出现

错误

class MemoryTest
{
public:
    MemoryTest()
    {
        p = new string("123456");
        cout << *p << endl;
    }
    ~MemoryTest()
    {
        delete p;
    }

private:
    string *p;
};

int main()
{
    // MemoryTest *str = new MemoryTest();
    // str->MemoryTest();
    MemoryTest str2;
    // str->~MemoryTest();
    str2.~MemoryTest();
    return 0;
}

正确

#include <complex>
#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

class MemoryTest
{
public:
    MemoryTest()
    {
        p = new string("123456");
        cout << *p << endl;
    }
    ~MemoryTest()
    {
        if(p)
        {
            delete p;
            p = nullptr;
        }
    }

private:
    string *p{nullptr};
};

int main()
{
    // MemoryTest *str = new MemoryTest();
    // str->MemoryTest();
    MemoryTest str2;
    // str->~MemoryTest();
    str2.~MemoryTest();
    return 0;
}

深拷贝和浅拷贝

#include <complex>
#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

class A
{
public:
    A(int _data) : data(_data){}
    ~A(){
        cout << data << endl;
    }
private:
    int data;
};
int main()
{
    A a(5);
    A b = a;
    return 0;
}

错误

class A
{
public:
    A(int _size) : size(_size)
    {
        data = new int[size];
    } 
    A(){};
    ~A()
    {
        delete [] data;
    } 
private:
    int* data;
    int size;
};

int main()
{
    A a(5), b = a; 
}

正确

class A
{
public:
    A(int _size) : size(_size)
    {
        data = new int[size];
    }
    A(){};
    A(const A& _A) : size(_A.size)
    {
        data = new int[size];
    } 
    ~A()
    {
        delete [] data;
    } 
private:
    int* data;
    int size;
};

int main()
{
    A a(5), b = a; 
}

new[] 和 delete[]

#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;
class MemoryTest
{
public:
    MemoryTest():id_(0)
    {
        cout << this << "default MemoryTest id =" << id_ << endl;
    }
    MemoryTest(int id):id_(id)
    {
        cout << this << "default MemoryTest id =" << id_ << endl;
    }
    ~MemoryTest()
    {
        cout << this << "default ~MemoryTest id =" << id_ << endl;
    }

private:
    int id_;
};

int main()
{
    MemoryTest *str = new MemoryTest[3];
    delete[] str;
    int *p = new int[20];
    delete p; // 内置类型析构函数没有意义时候删除不会报错,但是不建议这么使用
    return 0;
}

调用构造函数修改

#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

class MemoryTest
{
public:
    MemoryTest():id_(0)
    {
        cout << this << " default MemoryTest id =" << id_ << endl;
    }
    MemoryTest(int id):id_(id)
    {
        cout << this << " default MemoryTest id =" << id_ << endl;
    }
    ~MemoryTest()
    {
        cout << this << " default ~MemoryTest id =" << id_ << endl;
    }

private:
    int id_;
};

int main()
{
    MemoryTest *str = new MemoryTest[3];
    MemoryTest *tmp = str;

    for(int i = 0; i < 3; ++i)
        new (tmp++) MemoryTest(i);

    delete[] str;
    return 0;
}

placement new/placement delete

#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

class MemoryTest
{
public:
    MemoryTest():id_(0)
    {
        cout << this << " default MemoryTest id =" << id_ << endl;
    }
    MemoryTest(int id):id_(id)
    {
        cout << this << " default MemoryTest id =" << id_ << endl;
    }
    ~MemoryTest()
    {
        cout << this << " default ~MemoryTest id =" << id_ << endl;
    }

private:
    int id_;
};

int main()
{
    char *buf = new char[sizeof(MemoryTest)*3];
    MemoryTest *test = new (buf)MemoryTest();
    delete[] buf;
    return 0;
}

重载 ::operator new / ::operator delete

#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

void* myAlloc(size_t size)
{
    return malloc(size);
}
void myFree(void *pt)
{
    return free(pt);
}

class A
{
public:
    inline void * operator new (size_t size)
    {
        cout << "global new " << std::endl;
        return myAlloc(size);
    }
    inline void * operator new[] (size_t size)
    {
        cout << "global new[] " << std::endl;
        return myAlloc(size);
    }
    inline void operator delete (void *pt)
    {
        cout << "global delete " << std::endl;
        myFree(pt);
    }
    inline void operator delete[] (void *pt)
    {
        cout << "global delete[] " << std::endl;
        myFree(pt);
    }

};

int main()
{
    A *c = new A;
    delete c;
    A *c2 = new A[10];
    delete[] c2;
    return 0;
}

重载 new() / delete()

#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

void* myAlloc(size_t size)
{
    return malloc(size);
}
void myFree(void *pt)
{
    return free(pt);
}

class Bad : public exception
{

};
class A
{
public:
    A()
    {
        cout << "A" << std::endl;
    }
    A(int i) : id_(i)
    {
        cout << "A(int i)" << std::endl;
        // 本来抛出异常应该调用析构函数,但是我这里程序会进行不下去,应该是编译器做了优化,暂时未查询原因
        // throw Bad{};
    }
    inline void * operator new (size_t size)
    {
        cout << "operator new (size_t size)" << std::endl;
        return myAlloc(size);
    }
    inline void * operator new (size_t size, void *start)
    {
        cout << "operator new (size_t size, void *start) " << std::endl;
        return myAlloc(size);
    }
    inline void * operator new (size_t size, long extra)
    {
        cout << "operator new (size_t size, long extra)" << std::endl;
        return myAlloc(size+extra);
    }
    inline void * operator new (size_t size, long extra, char init)
    {
        cout << "operator new (size_t size, long extra, char init) " << std::endl;
        return myAlloc(size+extra);
    }

    inline void operator delete (void *, size_t t)
    {
        cout << "operator delete (void *, size_t t) " << std::endl;
    }
    inline void operator delete (void *, void *)
    {
        cout << "operator delete (void *, void *) " << std::endl;
    }
    inline void operator delete (void *, long)
    {
        cout << "operator delete (void *, long) " << std::endl;
    }
    inline void operator delete (void *, long, char)
    {
        cout << "operator delete (void *, long, char) " << std::endl;
    }

    void myPrint()
    {
        std::cout << "test" << std::endl;
    }

private:
    int id_;
};

int main()
{
    string s = "ccc";
    A *a = new A;
    A *a1 = new (a)A;
    A *a2 = new (100)A;
    A *a3 = new (100,'a')A;
    A *a4 = new (100)A(1);
    A *a5 = new (100,'a')A(1);
    A *a6 = new (a)A(1);
    A *a7 = new A(1);
    return 0;
}

空间划分

#include <stdlib.h>
#include <string>
#include <iostream>
#include <valarray>

using namespace std;

class Screen
{
public:
    Screen(int x):i(x)
    {

    }
    int get(){return i;};

    void * operator new (size_t size)
    {
        Screen *p;
        if(!freeStore)
        {
            size_t chunk = screenChunk * size;
            freeStore = p = reinterpret_cast<Screen * >(new char[chunk]);
            for(;p != &freeStore[screenChunk-1];++p)
            {
                p->next = p+1;
            }
            p->next = 0;
        }
        p = freeStore;
        freeStore = freeStore->next;
        return p;
    }
    void operator delete (void *p,size_t size)
    {
        static_cast<Screen *>(p)->next = freeStore;
        freeStore = static_cast<Screen *>(p);
    }

private:
    Screen *next;
    static Screen *freeStore;
    static const int screenChunk;

    int i;
};
Screen *Screen::freeStore = 0;
const int Screen::screenChunk = 24;
int main()
{
    size_t const N = 100;
    Screen *p[N];
    for(int i = 0; i < N; ++i)
    {
        p[i] = new Screen(i);
    }

    for(int i = 0; i < 10; ++i)
    {
        cout << p[i] << endl;
    }
    for(int i = 0; i < N; ++i)
    {
        delete p[i];
    }
    return 0;
}

改造

#include <stdlib.h>
#include <string>
#include <iostream>
#include <valarray>

using namespace std;

class Airplane
{
private:
    struct AirplaneRep
    {
        unsigned long miles;
        char type;
    };
    union {
        AirplaneRep rep;
        Airplane *next;
    };
    static const int BLOCK_SIZE;
    static Airplane *headOfFreeList;
public:
    unsigned long getMiles(){return rep.miles;}
    char getType(){return rep.type;}
    void set(unsigned long m ,char t)
    {
        rep.miles = m;
        rep.type = t;
    }

public:
    void * operator new(size_t size)
    {
        // 为了防止继承造成的空间大小不一致问题
        if(size != sizeof(Airplane))
            return ::operator new(size);

        Airplane *p = headOfFreeList;
        if(p)
            headOfFreeList = p->next;
        else
        {
            Airplane *newBlock = static_cast<Airplane *>(::operator new (BLOCK_SIZE * sizeof(Airplane)));
            for(int i = 1; i < BLOCK_SIZE -1; ++i)
            {
                newBlock[i].next = &newBlock[i+1];
            }
            newBlock[BLOCK_SIZE -1].next = 0;
            p = newBlock;
            headOfFreeList = &newBlock[1];
        }
        return p;
    }
    void operator delete (void *dataObj,size_t size)
    {
        if(dataObj == 0) return;
        if(size != sizeof(Airplane))
        {
            ::operator delete(dataObj);
            return;
        }
        Airplane *carcass = static_cast<Airplane *>(dataObj);
        carcass->next = headOfFreeList;
        headOfFreeList = carcass;
    }
};

const int Airplane:: BLOCK_SIZE = 512;
Airplane *Airplane::headOfFreeList;
int main()
{
    cout << sizeof(Airplane) << endl;
    size_t const N = 100;
    Airplane *p[N];
    for(int i = 0; i < N; ++i)
    {
        p[i] = new Airplane;
    }
    p[1]->set(1000,'A');
    p[2]->set(1000,'B');
    p[3]->set(1000,'C');
    p[4]->set(1000,'D');
    p[5]->set(1000,'E');
    p[6]->set(1000,'F');
    p[7]->set(1000,'G');
    p[8]->set(1000,'H');
    p[9]->set(1000,'I');
    for(int i = 0; i < 10; ++i)
    {
        cout << p[i] << endl;
    }
    for(int i = 0; i < N; ++i)
    {
        delete p[i];c
    }
    return 0;
}

分配器

#include <stdlib.h>
#include <string>
#include <iostream>
#include <valarray>

using namespace std;

class Allocator
{
public:
    void *allocate(size_t size)
    {
        obj *p;
        if(!freeStore)
        {
            size_t chunk = CHUNK * size;
            freeStore = p = (obj*) malloc(chunk);
            for(int i = 0; i < CHUNK -1; ++i)
            {
                p->next = (obj*)((char *)p +size);
                p = p->next;
            }
            p->next = nullptr;
        }
        p =freeStore;
        freeStore = freeStore->next;
        return p;
    }
    void deallocate(void *p,size_t size)
    {
        ((obj*)p)->next = freeStore;
        freeStore = (obj*)p;
    }

private:
    struct obj
    {
        struct obj *next;
    };
    obj *freeStore = nullptr;
    const int CHUNK = 5;
};

class Foo
{
public:
    long L;
    string str;
    static Allocator myAlloc;
public:
    Foo(long l):L(l){}
    void * operator new(size_t size)
    {
        return myAlloc.allocate(size);
    }
    void operator delete (void * p, size_t size)
    {
        return myAlloc.deallocate(p,size);
    }
};
Allocator Foo::myAlloc;

int main()
{
    Foo *p[100];
    cout << sizeof(Foo) <<endl;
    for(int i =0; i< 19; i++)
    {
        p[i] = new Foo(i);
        cout << p[i] << " " << p[i]->L << endl;
    }
    cout << 0x633b40-0x633ae0 << " " << 0x633b68-0x633b40 << endl;
    for(int i =0; i< 19; i++)
    {
        delete p[i];
    }
    return 0;
}

使用宏替换

#include <stdlib.h>
#include <string>
#include <iostream>
#include <valarray>

using namespace std;

class Allocator
{
public:
    void *allocate(size_t size)
    {
        obj *p;
        if(!freeStore)
        {
            size_t chunk = CHUNK * size;
            freeStore = p = (obj*) malloc(chunk);
            for(int i = 0; i < CHUNK -1; ++i)
            {
                p->next = (obj*)((char *)p +size);
                p = p->next;
            }
            p->next = nullptr;
        }
        p =freeStore;
        freeStore = freeStore->next;
        return p;
    }
    void deallocate(void *p,size_t size)
    {
        ((obj*)p)->next = freeStore;
        freeStore = (obj*)p;
    }

private:
    struct obj
    {
        struct obj *next;
    };
    obj *freeStore = nullptr;
    const int CHUNK = 5;
};

#define DECLARE_POOL_ALLOC_1() \
public:                      \
    void * operator new(size_t size){  return myAlloc.allocate(size); }   \
    void operator delete (void * p, size_t size){  return myAlloc.deallocate(p,size);  }                        \
protected:                             \
    static Allocator myAlloc;

#define IMPLEMENT_POOL_ALLOC_1(ClassName) \
    Allocator ClassName::myAlloc;

class Foo
{
    DECLARE_POOL_ALLOC_1();
public:
    long L;
    string str;
public:
    Foo(long l):L(l){}

};
IMPLEMENT_POOL_ALLOC_1(Foo);

int main()
{
    Foo *p[100];
    cout << sizeof(Foo) <<endl;
    for(int i =0; i< 19; i++)
    {
        p[i] = new Foo(i);
        cout << p[i] << " " << p[i]->L << endl;
    }
    cout << 0x633b40-0x633ae0 << " " << 0x633b68-0x633b40 << endl;
    for(int i =0; i< 19; i++)
    {
        delete p[i];
    }
    return 0;
}

new_handler

new (nothrow)Foo; 检查是否成功

typedef void (*new_handler)();

new_handler set_new_handler(new_handler p) throw();

当内存溢出的时候,C++提供一个内存检查函数,让用户提供

  1. 让更多的内存可用

  2. 调用abort()和exit();

#include <stdlib.h>
#include <iostream>
#include <valarray>
#include <new>
#include <cassert>

using namespace std;

void noMoreMemory()
{
    cerr << "out of memory" << endl;
    abort(); // 不abort 的话会不断打印这个err
}

int main()
{
    set_new_handler(noMoreMemory);
    int *p = new int[10000000000000];
    assert(p);
    return 0;
}

default delete

#include <stdlib.h>
#include <iostream>
#include <valarray>
#include <new>
#include <cassert>

using namespace std;

class Foo
{
public:
    // static void *operator new(size_t size) = default;
    // static void *operator delete(void *,size_t size) = default;
    static void *operator new[](size_t size) = delete;
    static void operator delete [](void *,size_t size) = delete;

};
int main()
{
    Foo *foo = new Foo;
    delete foo;

//    Foo *foo2 = new Foo[100];
//    delete foo[];
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

turbolove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值