new expression

  new会做两个动作:1、分配一块内存用来放object;2、分配好之后会调用构造函数。

//一个Person类
Person *p = new Person("liming",16); //初始化姓名和年龄;

  new这个表达式会被编译器看作是

Person *p;
try{
    void *mem = operator new(sizeof(Person)); //operstor new会调用malloc分配内存
    p=static_cast<Person*>(mem);
    p->Person::Person("liming",16);     //调用构造函数
}
catch (std::bad_alloc)
{
         ...  
}

delete expression

  delete某个object,编译器会先调用析构函数,这个object就会释放掉。

p->~Person();
operator delete(p);   //调用free()函数

array new和array delete

//一个person类
Person * p=new Person[3];
//调用三次默认构造
//无法通过参数赋初值
delete [] p;  //调用三次析构函数

一个demo

class Person
{
public:
    Person()
    {
        m_Age = 0;
        cout << "person的默认构造,this="<<this<<" age= "<<m_Age << endl;

    }
    Person(int age) :m_Age(age)
    {
        cout << "person的有参构造,this = "<<this<<"age= "<<m_Age << endl; 
    };
    ~Person()
    {
        cout << "person的析构函数,this= " << this << "age= " << m_Age << endl;
    }
    //在类中重载operator new,就不会去走全局作用域下的operator new
    //所谓内存管理就是把这些动作接管过来,弄一个内存池,但是这里并没做任何处理
    static void * operator new(size_t size);
    static void *operator new(size_t size, void *ptr); //plcement new
    static void operator delete(void *ptr, size_t size);
    static void * operator new[](size_t size);
    static void operator delete(void* ptr1, void* ptr2); //对应placement new的operator delete
    static void operator delete[](void *ptr, size_t size);
private:
    int m_Age;
};
void * Person:: operator new(size_t size)
{
    Person *p = (Person*)malloc(size);
    cout << "my operator new" << endl;
    return p;
}
void * Person:: operator new(size_t size,void *ptr)
{
    return ptr;
}
void Person::operator delete(void *ptr, size_t size)
{
    free(ptr);
    cout << "my operator delete" << endl;
}
void* Person::operator new[](size_t size)
{
    Person *p = (Person*)malloc(size);
    cout << "my operator new []" << endl;
    return p;
}
void Person::operator delete[](void *ptr, size_t size)
{
    free(ptr);
    cout << "my operator delete[]" << endl;
}
void Person::operator delete(void *ptr1, void *ptr2)
{
    free(ptr1);
    cout << "operator delete(void *,void *)" << endl;
}
void test01()
{
    Person *Parry = new Person[3];//会调用默认构造
    Person *temp = Parry;
    cout << "parry= " << Parry << "temp=" << temp << endl;
    for (size_t i = 0; i < 3; i++)
    {
        new(temp++)Person(i + 10); //有参构造 placement new 允许我们将object构造于已经分配的内存中。
    }
    cout << "parry=" << Parry << "temp=" << temp << endl;
    delete[] Parry;
}

 

placement  new

  placement new 允许我们将object构造于已经分配的内存中。但是没有所谓的placement delete,因为placement new没有分配内存。但是在分配好内存之后,如果出现构造失败抛出异常,需要有对应的operator delete来释放这块内存。

  以上demo中的new(temp)Person(1),编译器将他转换成

void *mem = operator new(sizeof(Person),temp);//不做事
            /*void* operator new(size_t,void *loc)
            {    return loc;}*/
temp = static_cast<Person*>(mem);
temp->Person::Person(1);

针对一个class设计出一个内存管理

  减少malloc()的次数、减少cookie用量可以节省空间,提高效率。由此可以使用内存池来对内存管理,即一次malloc()一大块内存,再切成若干小块,用户要求几块给几块,剩下的区块用指针连接起来。可以通过重载operator new/operator delete来设计内存池。

设计一个alloctor

class myallocator{
private:
    struct obj{
        struct obj*next;       //嵌入式指针
    };
public:
    void * allocate(size_t size);
    void dellocate(void *, size_t size);
private:
    obj *freeStore = nullptr;
    const int CHUNK = 10;
};
void * myallocator::allocate(size_t size)
{
    obj *p;
    if (!freeStore)
    {
        size_t chunk = CHUNK*size;
        freeStore = p = (obj*)malloc(chunk);//一次malloc一大块
        for (size_t 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 myallocator::dellocate(void *p, size_t size)
{
    ((obj*)p)->next = freeStore;
    freeStore = (obj*)p;
}

在一个class中使用内存池

class Person
{
public:
    Person()
    {
        m_Age = 0;
    }
    static void *operator new(size_t size) //重载operator new
    {
        return myAlloc.allocate(size);
    }
    static void operator delete(void*ptr, size_t size)
    {
        return myAlloc.dellocate(ptr, size);
    }
    int m_Age;
    static myallocator myAlloc;
};
myallocator Person::myAlloc;
void  test01()
{
    Person* arry[5];
    cout << "sizeof(person)=" << sizeof(Person) << endl;
    for (size_t i = 0; i < 5; i++)
    {
        arry[i] = new Person;
        cout << arry[i] << "    " << arry[i]->m_Age << endl;
    }
    for (size_t i = 0; i < 5; i++)
    {
        delete arry[i];
    }
    
}

 内存池

准备工作

    enum{ __ALIGN = 8 };//小区块的上调边界
    enum{ __MAX_BYTES = 128 };//区块上限
    enum { __NFREELISTS = __MAX_BYTES / __ALIGN }; //自由链表的长度
    //嵌入式指针
    struct obj{
        struct obj*free_list_link;
    };    
class alloc{
    private:
        static size_t ROUND_UP(size_t bytes) //上调到8的倍数
        {
            return(((bytes)+__ALIGN - 1) & ~(__ALIGN - 1));
        }

    private:
        static obj* free_list[__NFREELISTS];  //16个自由链表
        //用户要的内存应该由第几号链表负责
        static size_t freelist_index(size_t bytes)
        {
            return (bytes + __ALIGN - 1) / __ALIGN - 1;
        }
        //注水
        static void * refill(size_t n);
        static void *chunk_alloc(size_t size, int &nobjs);
        static char *start_free; //战备池的开始端
        static char * end_free;//战备池的末端
        static size_t heap_size;//总的分配量
    public:
        //分配大小为n的空间
        static void * allocate(size_t n)
        {
            obj **my_free_list;//指向自由链表的起点
            obj * result;
            //要的字节数大于128
            if (n > (size_t)__MAX_BYTES)
            {
                //交给malloc
                return (std::malloc(n));
            }
            //由第几号链表负责
            my_free_list = free_list + freelist_index(n);
            result = *my_free_list;//第一块
            if (result == 0)//判断这个链表是否为空
            {
                //注水
                void * r = refill(ROUND_UP(n));
                return r;
            }
            //第一块给出去以后,指向第二块
            *my_free_list = result->free_list_link;
            return result;
        }
        static void  deallocate(void *p, size_t n)
        {
            obj*q = (obj*)p;
            obj ** my_free_list;
            if (n > (size_t)__MAX_BYTES)
            {
                //第一级
                std::free(p);
                return;
            }
            my_free_list = free_list + freelist_index(n);
            q->free_list_link = *my_free_list;
            *my_free_list = q;
        }

    };
//类外初始化
    char *alloc::start_free = nullptr;
    char *alloc::end_free = nullptr;
    size_t alloc::heap_size = 0;
    obj * alloc::free_list[__NFREELISTS] = { nullptr, nullptr, nullptr, nullptr,
        nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
        nullptr, nullptr, nullptr, nullptr, nullptr };

    void *alloc::refill(size_t n) //n是8的倍数
    {
        int nobjs = 20;//预设取20
        char * chunk = (char *)chunk_alloc(n, nobjs);
        obj **my_free_list;
        obj*result;
        obj *current_obj;
        obj*next_obj;
        int i;
        if (1 == nobjs)  return chunk;
        my_free_list = free_list + freelist_index(n);

        result = (obj*)chunk;
        *my_free_list = next_obj = (obj*)(chunk + n);
        for (i = 1;; ++i)
        {
            current_obj = next_obj;
            next_obj = (obj*)((char*)next_obj + n);
            if (nobjs - 1 == i)
            {
                current_obj->free_list_link = 0;
                break;
            }
            else
            {
                current_obj->free_list_link = next_obj;
            }
        }
        return result;

    }
    void *alloc::chunk_alloc(size_t size, int &nobjs)
    {
        char * result;
        size_t total_bytes = size*nobjs;
        size_t bytes_left = end_free - start_free;
        if (bytes_left > total_bytes)
        {
            //战备池很充足
            result = start_free;
            start_free += total_bytes;
            return result;
        }
        else if (bytes_left >= size){
            nobjs = bytes_left / size;
            total_bytes = size*nobjs;
            result = start_free;
            start_free += total_bytes;
            return result;
        }
        else
        {//战备池不足以满足一个
            size_t bytes_to_get =
                2 * total_bytes + ROUND_UP(heap_size >> 4);
            if (bytes_left > 0)
            {
                obj **my_free_list = free_list + freelist_index(bytes_left);

                //处理碎片
                ((obj*)start_free)->free_list_link = *my_free_list;
                *my_free_list = (obj*)start_free;
            }
            start_free = (char *)malloc(bytes_to_get);
            if (0 == start_free)
            {
                int i;
                obj **my_free_list;
                obj *p;
                for (i = size; i < __MAX_BYTES; i += __ALIGN)
                {
                    my_free_list = free_list + freelist_index(i);
                    p = *my_free_list;
                    if (0 != p)
                    {
                        *my_free_list = p->free_list_link;
                        start_free = (char *)p;
                        end_free = start_free + i;
                        return (chunk_alloc(size, nobjs));
                    }
                }
                //      
                std::printf("out of memory");
                end_free = nullptr;
                throw std::bad_alloc();
            }
            heap_size += bytes_left;
            end_free = start_free + bytes_to_get;
            return(chunk_alloc(size, nobjs));

        }
    }
}

测试程序

class Person
{
public:
    Person()
    {
        m_Age = 0;
    }
    static void *operator new(size_t size) //重载operator new
    {
        return myAlloc.allocate(size);
    }
    static void operator delete(void*ptr, size_t size)
    {
        return myAlloc.deallocate(ptr, size);
    }
    int m_Age;
    static alloc myAlloc;
};
alloc Person::myAlloc;
int main()
{
    Person* arry[5];
    std::cout << "sizeof(person)=" << sizeof(Person) << std::endl;
    for (size_t i = 0; i < 5; i++)
    {
        arry[i] = new Person;
        std::cout << arry[i] << "    " << arry[i]->m_Age << std::endl;
    }
    for (size_t i = 0; i < 5; i++)
    {
        delete arry[i];
    }

    system("pause");
}