上下文:我正在一个项目中,客户端需要我们使用自定义动态内存分配,而不是从堆栈中分配对象。请注意,有关对象的大小在编译期间已知,甚至不需要动态分配。这让我感到奇怪,
在某些情况下,自定义对象的动态内存分配比从堆栈中分配对象更好? (在编译过程中知道大小)
一个例子。如果Dog
是一个类,那么他们不只是声明Dog puppy;
,而是希望我们做
Dog* puppy = nullptr;
custom_alloc(puppy);
new(puppy) Dog(); // the constructor
// do stuff
puppy->~Dog(); // the destructor
custom_free(puppy)
我们不知道真正的custom_alloc
函数。为了使程序运行,给定的custom_alloc
函数将是malloc
的包装。并且custom_free
将是free
我不喜欢这种方法,并且想知道这种方法何时真正有用,或者他们真正想通过此方法解决什么。
答案 0 :(得分:1)
可能的原因:
堆栈大小有限;虽然典型的线程库会为每个线程的堆栈分配1-10 MB的内存,但对于希望同时启动数百或数千个线程的应用程序(例如,高流量的Web服务器; Microsoft IIS以前使用限制为256 KB,对于64位设置,最多只能增加到512 KB。
您可能想在函数返回后保留一个对象(不使用全局变量)。尽管NRVO和/或移动语义确实意味着按值返回对象通常相对便宜,但是当NRVO不适用时,围绕单个指针进行复制比其他任何方法都便宜。
审计/跟踪:他们可能想对特定类型使用其自定义函数来跟踪内存分配模式
持久性存储:分配器可以由内存映射文件支持;对于结构化数据,该文件的长期存储量可能翻倍
性能:Custom allocators (e.g. Intel's TBB) have been known to dramatically reduce runtime in certain circumstances。这是使用自定义分配器而不是默认分配器的理由。自定义分配器通常不会超过堆栈存储(在真正特殊情况下,可以通过从堆栈中删除大对象并将它们放在自己的专用存储中来改善内存局部性)。
< / li>(这是一个可怕的主意),避免了异常处理清理开销。如果您的类是RAII,则必须生成代码以在发生异常的情况下沿各种代码路径清理它们。原始指针不会生成任何此类代码。当然,如果您自己不采取措施对异常进行清除,这意味着内存泄漏,但是在极少数情况下(例如,当您期望程序完全退出,并且您希望操作系统处理内存清除时),这可能提供次要的“好处”。
上述各项的组合:他们可能希望能够通过链接不同的运行时库以提供custom_alloc
所有这些,他们做到这一点的方法非常糟糕;需要手动放置new
并且析构函数调用是不愉快的(std::unique_ptr
/ std::shared_ptr
通过提供可为您完成此工作的自定义删除函子可以有所帮助,但这仍然很丑陋)。通常,如果需要自定义分配器,则可以为operator new
/ operator delete
定义适当的重载。这样,避免栈分配(无论出于何种原因)并没有那么令人讨厌。您只需用std::unique_ptr
(通过std::make_unique
创建)替换逻辑上堆栈分配的变量,您的代码就相当简单。