一些小记录

看侯捷大佬的内存管理时的一点记录。

operator new/delete

全局的重载

::operator new/new[]/delete/delete[]可以重载,但是不能在命名空间内重载。重载之后,使用new的时候会调用::operator new。如果在类里重载了operator new,则new 类的对象时会调用类里的函数。

#include<iostream>
using namespace std;

void* operator new(size_t size)
{
    cout<<"my operator new(), size is "<<size<<endl;
    return malloc(size);
}

void* operator new[](size_t size)
{
    cout<<"my operator new[](), size is "<<size<<endl;
    return malloc(size);
}

void operator delete(void* ptr)
{
    cout<<"my operator delete()\n";free(ptr);
}

void operator delete[](void* ptr)
{
    cout<<"my operator delete[]()\n";free(ptr);
}

void test1()
{
    int *a = new int;
    int *b = new int[10];

    delete a;
    delete b;
}


int main(int argc, char const *argv[])
{
    test1();
    return 0;
}

这里delete没有调用重载的delete,不知道为啥。将指针转为void*时由会调用重载的delete,但编译时有warning。

类里的重载:

在类里重载为静态函数,因为非静态函数需要类的对象才可以调用。
例子如下:

class A{
        public:
        A(){}
        ~A(){}
        static void* operator new(size_t size);
        static void operator delete(void* ptr);
        static void* operator new[](size_t size);
        static void operator delete[](void* ptr);
    };

    void* A::operator new(size_t size)
    {
        cout<<"operator new in class A, size is "<<size<<endl;
        void* ret = malloc(size);
        cout<<"address is "<<ret<<endl;
        return ret;
    }

    void A::operator delete(void* ptr)
    {
        cout<<"operator delete in class A"<<endl;
        free(ptr);
    }

    void* A::operator new[](size_t size)
    {
        cout<<"operator new[] in class A, size is "<<size<<endl;
        void* ret = malloc(size);
        cout<<"address is "<<ret<<endl;
        return ret;
    }

    void A::operator delete[](void* ptr)
    {
        cout<<"operator delete[] in class A"<<endl;       
        free(ptr);
    }
    
    void test_size()
    {
        cout<<sizeof(A)<<endl;
        A* a = new A[10];
        cout<<"address a "<<a<<endl;

        uint64_t val = *((uint64_t *)a - 1);
        cout<<"8 Bytes as uint64: "<<val<<endl;
        delete[] a;
    }

运行test_size时输出如下:

1
operator new[] in class A, size is 18
address is 0xea6d10
address a 0xea6d18
8 Bytes as uint64: 10
operator delete[] in class A

可以看到,没有成员时,类的对象占一个字节,并且new A[10]会多申请8个字节,返回的首地址是申请的内存首地址0xe36d10+0x8=a0xe36d18。这8个字节应该是64位无符号整数,等于申请的类的对象的数量。

类里元素的分布

这个感觉和结构体很像,默认的4字节对齐,从上到下,不区分公有和私有。在上边的基础上,比如:


private:
            int a;
            char b;
            int c;

size是12.char虽然占1字节,但是为了4字节对齐,后边三个字节空着。


private:
            int a;
            char b;
            int c;

public:
            char d;

size是16


public:
            int e;

        private:
            int a;
            char b;
            int c;

        public:
            char d;

size是20


然后打印他们的地址:

#define print_address(x) cout<< #x <<" : "<<(void*)x<<endl;
#define print_value(x) cout<< #x <<" : "<<x<<endl;
void print(){
            print_address(this);
            print_address(&a);
            print_address(&b);
            print_address(&c);
            print_address(&d);
            print_address(&e);
}

void test_adress()
    {
        A a;
        a.print();
        A* b= new A();
        b->print();
        delete b;
    }

输出如下:

this : 0x61fdc0
&a : 0x61fdc4
&b : 0x61fdc8
&c : 0x61fdcc
&d : 0x61fdd0
&e : 0x61fdc0
operator new in class A, size is 20
address is 0xdc6d10
this : 0xdc6d10
&a : 0xdc6d14
&b : 0xdc6d18
&c : 0xdc6d1c
&d : 0xdc6d20
&e : 0xdc6d10
operator delete in class A

可以看到地址顺序应该是:e,a,b,c,d,每次加4字节。

然后可以通过这个地址来读写类的成员变量,不管是不是私有,有点离谱。

//打印值
void print_val()
        {
            print_value(a);
            print_value(b);
            print_value(c);
            print_value(d);
            print_value(e);
        }
void test_change_private()
    {
        A* a= new A();
        a->print_val();
        int* tmp = (int*)a;
        tmp[0]=10;//int e
        tmp[1]=20;//int a
        *(char*)(tmp+2) = 'b'; //char b
        tmp[3] = 40;//int c
        *(char*)(tmp+4) = 'd'; //char d

        cout<<"change val:\n";
        a->print_val();

        delete a;
    }

输出结果如下(我没有初始化,第一次输出可能是随机的)

operator new in class A, size is 20
address is 0x1016d10
a : 0
b : P
c : 0
d :
e : 16847440
change val:
a : 20
b : b
c : 40
d : d
e : 10
operator delete in class A

注:类和结构体一样可以用这个#define PACKED __attribute__((packed, aligned(1))),用来使成员1字节对齐,也就是强制压缩,将其加在类后,再看看sizeof(A)

class A{
...
} PACKED;

输出:

17
operator new[] in class A, size is 178
address is 0x1f6d10
address a 0x1f6d18
8 Bytes as uint64: 10
operator delete[] in class A

输出的A的大小变为了17,最后一个char只占1字节,如果在最后一个char后边定义一个4字节的int,那么类的对象占字节数就是24。感觉就是类里元素还是4字节对齐,到了最后一个元素就是1字节(不考虑对齐)。

注:编译器为mingw64/bin/g++.exe

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值