我通过重载new和delete,我在一本书中读到,new和malloc之间的区别是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
,因为它的怪癖。)
超载new
与constructors
无关。class
可以提供自己的操作符new()
,它负责在构造函数调用之前分配内存。这对于优化小对象池非常有用,例如,您还可以查看操作符new()
的各种重载,包括所谓的"placement new",允许为诸如就地构造(用户提供的缓冲区),文件/行诊断等提供任意参数。
注意:可以不"重载";或";overwrite"标准C库函数,但通常的做法是允许您覆盖它的一个合理的子集。
一般来说,链接器不知道给定的对象文件是用什么语言写的,它在明显较低的知识水平上工作——与对象文件的外部符号,其中应该是唯一的,在所有的对象文件和共享库被链接在一起,因为链接器本身不能随意删除命令行上给定的具有重复符号的对象。值得注意的例外是静态库(a)——如果它有助于删除重复的外部符号,则允许链接器从存档中删除任何项或项。
允许重写库函数由两部分组成:
-
编译器的语法将函数标记为可重载的——适当的外部符号将被标记为"弱链接"。例如,对于
gcc
:`__attribute__((weak)) void *malloc(size_t size)`
-
动态链接器(
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。