我们可以重载malloc()吗?

Can we overload malloc()?

本文关键字:malloc 重载 我们      更新时间:2023-10-16

我通过重载newdelete,我在一本书中读到,newmalloc之间的区别是new调用构造函数,返回调用变量的类型,第三个区别是我们可以在类的基础上重载new,而malloc不能,有人也可以通过类的基础来解释这个类吗?

全局命名空间中的::operator new可以被替换(覆盖),而不能被重载。这将导致使用重写而不是标准库提供的函数。并且可以提供my_class::operator new,这样就可以在new my_class表达式中使用,这也不同于重载。

重载new只在使用位置new语法时才会起作用:

new ( memory_pool, 123, other_args ) my_class( constructor_args )

new关键字之后的双亲中提供额外的参数会导致operator new的另一个重载调用,额外的参数附加在size_t之后,指定需要多少内存。

你当然可以像重载其他函数一样重载::malloc,通过定义一个接受不同参数的版本:

void *malloc( std::size_t size, allocation_pool &pool );

这只是一个叫做malloc的新函数。但是调用带有显式std::限定条件的库函数更好,并且添加std::malloc重载将违反库的规则。

你不能代替std::malloc。唯一可以替换的函数是::operator new的标准变体。没有特定于类的malloc这样的东西,因为它不接受一个参数来指示哪个类将进入返回的内存块。malloc不知道你将用返回的内存做什么;它只是一团字节。

作为程序组织的问题,可能应该给出一个更专门的分配器,并作为另一个名称调用,而不是malloc。如果需要根据类型调用不同的函数,可以使用模板,例如

template< typename allocated >
void *my_allocate( std::size_t sz ); // maybe "sz" param is unnecessary.

还可以专门化std::allocator< my_class >及其成员函数allocate。然后,各种标准库工具将调用您的函数,尽管没有自定义new。(您可能会避免太深入自定义new,因为它的怪癖。)

超载newconstructors无关。class可以提供自己的操作符new(),它负责在构造函数调用之前分配内存。这对于优化小对象池非常有用,例如,您还可以查看操作符new()的各种重载,包括所谓的"placement new",允许为诸如就地构造(用户提供的缓冲区),文件/行诊断等提供任意参数。

注意:可以不"重载";或";overwrite"标准C库函数,但通常的做法是允许您覆盖它的一个合理的子集。

一般来说,链接器不知道给定的对象文件是用什么语言写的,它在明显较低的知识水平上工作——与对象文件的外部符号,其中应该是唯一的,在所有的对象文件和共享库被链接在一起,因为链接器本身不能随意删除命令行上给定的具有重复符号的对象。值得注意的例外是静态库(a)——如果它有助于删除重复的外部符号,则允许链接器从存档中删除任何项或项。

允许重写库函数由两部分组成:

  1. 编译器的语法将函数标记为可重载的——适当的外部符号将被标记为"弱链接"。例如,对于gcc:

    `__attribute__((weak)) void *malloc(size_t size)`
    
  2. 动态链接器(ld.so),支持弱链接。

尚不清楚malloc()是否在特定的共享libc中被声明为弱符号,但通常情况下它是弱符号,因此,您很有可能能够覆盖它,但是您的体验可能会有所不同。

是的,我们可以重载标准库函数malloc。请看下面的代码片段:

    #include <iostream>
    void malloc(void)
    {
        puts("malloc");
    }
    int main()
    {
        int *p= (int*)malloc(8);
        malloc();
        free(p);
        return 0;
    }

这段代码打印malloc

同样,下面是这个程序的内存的TEXT部分的片段:

    0000000000400744 T _Z6mallocv
    0000000000400770 T main

,下面是来自DYNAMIC SYMBOL TABLE

的代码片段
    0000000000000000      DF *UND*  00000000000001d2  GLIBC_2.2.5 malloc
    0000000000000000      DF *UND*  00000000000001a5  GLIBC_2.2.5 __libc_start_main
因此,我们可以重载标准库函数,如c++中的malloc。