C++ 内存管理 基本部分

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

内存管理


基本体


分配内存和释放内存

方式

分配 释放 类别 能否重载
malloc() free() c函数 不可
new delete c++表达式 不可
::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;
}


目录
相关文章
|
19天前
|
存储 Java C++
C++ 引用和指针:内存地址、创建方法及应用解析
C++中的引用是现有变量的别名,创建时需用`&`运算符,如`string &meal = food;`。指针存储变量的内存地址,使用`*`创建,如`string* ptr = &food;`。引用必须初始化且不可为空,而指针可初始化为空。引用在函数参数传递和提高效率时有用,指针适用于动态内存分配和复杂数据结构操作。选择使用取决于具体需求。
38 9
|
23天前
|
存储 Linux C语言
【C++初阶】6. C&C++内存管理
【C++初阶】6. C&C++内存管理
34 2
|
2月前
|
存储 程序员 Linux
1024程序员节特辑 | C++入门指南:内存管理(建议收藏!!)
1024程序员节特辑 | C++入门指南:内存管理(建议收藏!!)
41 0
|
2月前
|
存储 监控 算法
【C++ 软件设计思路】高效管理历史任务记录:内存与磁盘结合的策略解析
【C++ 软件设计思路】高效管理历史任务记录:内存与磁盘结合的策略解析
56 0
|
6天前
|
存储 缓存 算法
C++从入门到精通:4.6性能优化——深入理解算法与内存优化
C++从入门到精通:4.6性能优化——深入理解算法与内存优化
|
6天前
|
存储 程序员 编译器
C++从入门到精通:3.4深入理解内存管理机制
C++从入门到精通:3.4深入理解内存管理机制
|
7天前
|
存储 人工智能 程序员
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
37 1
|
7天前
|
C语言 C++
【C++基础(九)】C++内存管理--new一个对象出来
【C++基础(九)】C++内存管理--new一个对象出来
|
8天前
|
存储 编译器 Linux
c++的学习之路:8、内存管理与模板
c++的学习之路:8、内存管理与模板
8 0
|
13天前
|
存储 Linux C语言
C/C++之内存旋律:星辰大海的指挥家
C/C++之内存旋律:星辰大海的指挥家
23 0