Как может перегруженный оператор new вызывать бесконечные циклы? - PullRequest
0 голосов
/ 09 июля 2020

Я читал книгу под названием «Практическое системное программирование с помощью C ++». На странице 320 говорится, что перегрузка оператора new может вызвать бесконечные циклы, поэтому этого следует избегать.

Эти перегрузки влияют на все выделения, в том числе используемые библиотекой C ++, поэтому следует соблюдать осторожность. принимается при использовании этих перегрузок, поскольку бесконечные циклические c рекурсии могут возникнуть, если внутри этих функций выполняется выделение. Например, нельзя использовать структуры данных, такие как std :: vector и std :: list, или функции отладки, такие как std :: cout и std :: cerr, поскольку эти средства используют операторы new () и delete () для выделения памяти. .

Итак, как этот фрагмент кода может вызвать бесконечное l oop, и почему я не должен использовать с ним cout и vector? Это был фрагмент кода в книге. Я пытался использовать vector, cout (внутри оператора new), push_back, но не могу воспроизвести ситуацию. Итак, когда именно это может произойти?

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

1 Ответ

1 голос
/ 09 июля 2020

Простое указание std::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) Недостаточно просто построить std::vector, потому что он может не распределяться. std::vector обычно выделяется только тогда, когда вы как-то об этом говорите. Он будет расширяться, когда вы попытаетесь что-то добавить к нему, или вы можете сказать «будь хотя бы таким большим» с помощью reserve. б) Вы должны откуда-то позвонить operator new, чтобы вызвать l oop (здесь это в new в main).

...