首页 > 解决方案 > 重载的“operator new”如何导致无限循环?

问题描述

我正在阅读一本名为“Hands-On System Programming with C++”的书。它在第 320 页上说,重载new运算符会导致无限循环,因此应该避免。

这些重载会影响所有分配,包括 C++ 库使用的分配,因此在利用这些重载时应小心,因为如果在这些函数内执行分配,可能会发生无限循环递归。例如,std::vector 和 std::list 等数据结构或 std::cout 和 std::cerr 等调试函数不能使用,因为这些工具使用 new() 和 delete() 运算符来分配内存.

那么,这段代码怎么会导致死循环,为什么不应该用coutandvector呢?这是书中的一段代码。我尝试使用vector, cout(在new运算符内部)push_back,但无法复制这种情况。那么,这究竟什么时候会发生呢?

void* operator new (size_t size){
    if(size > 1000) page_counter++;
    return malloc(size);
}

标签: c++overloadinginfinite-loopnew-operator

解决方案


只需告诉 astd::vector分配一些内存operator new就可以了:

void *operator new(std::size_t size) {
    // std::vector<int>::reserve calls std::allocator<int>::allocate calls (this) operator new calls ...
    std::vector<int>().reserve(999);
    return std::malloc(size);
}

int main() {
    int *p = new int(42);
    // OFC, this is undefined behavior, so we *could* reach this, but... we don't, which means it definitely is UB
    std::cout << "Shouldn't reach this!\n";
}

Godbolt显示它崩溃了

请注意, a) 仅构造 a 是不够的std::vector,因为它可能无法分配。std::vector通常仅在您以某种方式告诉它时才分配。当您尝试向其添加内容时,它会扩展,或者您可以用reserve. b)您必须operator new从某个地方调用才能触发循环(这里它在newin内main)。


推荐阅读