我是否应该将所有对new/delete的调用集中到一个类

Should I centralize all calls to new/delete to a single class?

本文关键字:集中 调用 一个 delete 是否 new      更新时间:2023-10-16

目前,我的所有对象都管理自己的内存,通常在构造函数中分配new,并在析构函数中使用delete。 这目前有效,但我拥有的使用任意内存量的类数量正在增长。 new本质上是一个"请求"这一事实也困扰着我,因为这些对象中没有代码来处理被告知"否",如果我不需要,我不想依赖异常处理。

  • 在性能方面是否有益 完全将所有分配内存的调用屏蔽到处理的单个类堆上的每个内存分配,可能分配大块一次并使用放置新来处理引用?

  • 在较小的类中使用内存分配是否是一个足够大的问题,甚至会为此烦恼?

  • 我是否仍然可以使用 STL 容器并强制它们使用堆 I提供?

提前谢谢你!

我是否仍然可以使用 STL 容器并强制它们使用我提供的堆?

STL 容器接受自定义分配器:

http://en.wikipedia.org/wiki/Allocator_(C%2B%2B(#Custom_allocators

下面是一个包含示例链接的线程:

令人信服的自定义C++分配器示例?

它在性能方面是否有好处...?

只能通过编写应用程序、提出一组可重现的测试方案以及在探查器中运行代码来查找。 如果您发现内存分配是运行时间的重要组成部分,那么您可能会从更好的分配策略中受益。

如果你可以将程序分解为功能级别,并且可以为每个情况提出现实的场景,那么您就不必让整个程序来执行此操作。 但请记住,花在优化上的时间是可以花在测试或编码新功能上的时间:) 做必要的事情,不再...

在较小的类中使用内存分配是否是一个足够大的问题,甚至会为此烦恼?

根据您的程序、您对大分配障碍的敏感程度、循环分配的频率等,这是可能的。 简介:)

在开发应用时,您仍然可以对分配敏感 - 尽可能创建自动存储(堆栈本地(变量,并仅在必要时动态分配。

我不太确定我是否理解您的问题。也就是说,在 C++03 中将 STL 容器与自定义堆一起使用将具有挑战性,因为分配器被视为无状态。另外,为什么不想依赖异常处理?您是否知道有新版本的no_throw版本?

编辑:new的无抛掷版本是这样调用的:new (std::nothrow) Type[size];。如果分配失败,它将返回一个空指针(0(,而不是抛出std::bad_alloc

我是否仍然可以使用 STL 容器并强制它们使用我提供的堆?

是的,查找 STL 分配器。

将所有分配内存的

调用完全屏蔽到处理堆上每个内存分配的单个类,一次可能分配大块并使用放置 new 来处理引用,这在性能方面是否有益?

这基本上就是mallocnew的良好实现所做的。我不建议自己动手,除非情况非常注重性能并且其他一切都已优化。为什么?因为通过内存管理进行良好和深思熟虑甚至很难获得无错误,更不用说优化工作了。

在较小的类中使用内存分配是否是一个足够大的问题,甚至会为此烦恼?

这取决于,如果您正在用 16k 内存对咖啡机或游戏设备进行编程,但在普通台式计算机或笔记本电脑上可能不会。还要记住,堆栈非常快(分配和访问(,而堆在分配方面要差得多,在使用方面稍微(不太确定TBH(,因此在日常情况下,您希望更喜欢堆栈。

你说你在构造函数中调用new...这真的有必要吗?我的意思是,而不是这个...

class A{
    std::vector<int>* v;
    A( int vectorSize ){
       v = new std::vector<int>( vectorSize, 0 );
    }
    ~A(){
       delete v;
    }
};

。这样做总是可以的:

class A{
    std::vector<int> v;
    A( int vectorSize ):
       v( vectorSize, 0 ){
    }
};

这样就可以避免使用堆。只有在别无选择的情况下,才应使用堆。

除此之外,正如其他人所说,编写自定义分配器是一项非常复杂的任务,只能在性能关键型场景中完成

我以前做过这个,这是我的经验:

  1. 它很快就会变得非常混乱。特别是因为您现在掌握了内存分配,并且必须处理诸如碎片和重入之类的事情。
  2. 但是,由于能够绕过操作系统开销,我已经看到性能提高了 20% 以上

对于您的最后一个问题,我认为有一种方法可以让他们使用自定义分配器,但我以前从未这样做过。我的大部分编码都是用 C 语言完成的。

编辑:

根据您的评论,这里有一个更新。您实际上不必处理构建分配器的问题。您可能只需将所有内存分配指向自定义类即可。然后,您的自定义类将调用malloc()new并捕获返回的任何 NULL 或异常。

(尽管用您自己的malloc()替换每个new需要一些工作。