Что делает новый оператор C++, кроме выделения и вызова ctor?

Каковы все другие вещи new Оператор делает, кроме выделения памяти и вызова конструктора?

3 ответа

Решение

Стандарт C++ имеет это сказать о единой объектной форме (обычно используемой форме) оператора new из <new> заголовок:

Требуемое поведение:

Вернуть ненулевой указатель в соответствующим образом выровненное хранилище (3.7.3) или же вызвать исключение bad_alloc. Это требование является обязательным для замещающей версии этой функции.

Поведение по умолчанию:

- Выполняет цикл: внутри цикла функция сначала пытается выделить запрошенное хранилище. Влечет ли попытка вызова функции библиотеки Standard C malloc, не уточняется.

- Возвращает указатель на выделенное хранилище, если попытка была успешной. В противном случае, если последний аргумент для set_new_handler() был нулевым указателем, выведите bad_alloc.

- В противном случае функция вызывает текущий new_handler (18.4.2.2). Если вызванная функция возвращается, цикл повторяется.

- Цикл завершается, когда попытка выделить запрошенное хранилище успешна или когда вызываемая функция new_handler не возвращается.

В стандарте есть много других вещей, которые можно сказать о новом операторе и динамическом распределении памяти (очень много, чтобы сказать), но я думаю, что список "Поведение по умолчанию" довольно хорошо обобщает основы нового оператора.

Я написал объяснение того, что он делает в этом ответе. Это объясняет как

  • new получает память
  • new обрабатывает сбой памяти
  • new обрабатывает исключения конструктора
  • new обрабатывает специальные варианты размещения

Майкл объяснил, как функция выделения по умолчанию (::operator new) прекрасно получает память и как она обрабатывает ошибки. Я видел ваш вопрос о том, где размер объекта хранится в его комментариях. Ответ: размер не сохраняется, если не необходим. Помните, что C не нужен размер для free (и:: оператор new можно просто использовать malloc):

void * memory = malloc(x);
free (memory); // no need to tell it the size

Вот пример, где вы видите, как сохранение размера влияет на размер выделения для формы массива нового выражения (не охвачено моим другим ответом):

#include <cstddef>
#include <iostream>

struct f {
    // requests allocation of t bytes
    void * operator new[](std::size_t t) throw() {
        void *p = ::operator new[](t);
        std::cout << "new    p: " << p << std::endl;
        std::cout << "new size: " << t << std::endl;
        return p;
    }

    // requests deleting of t bytes starting at p
    void operator delete[](void *p, std::size_t t) throw() {
        std::cout << "delete p: " << p << std::endl;
        std::cout << "size    : " << t << std::endl;
        return ::operator delete[](p);
    }
};

int main() {
    std::cout << "sizeof f: " << sizeof (f) << std::endl;

    f * f_ = new f[1];
    std::cout << "&f_     : " << f_ << std::endl;
    delete[] f_;
}

Он распечатает что-то вроде этого:

sizeof f: 1
new    p: 0x93fe008
new size: 5
&f_     : 0x93fe00c
delete p: 0x93fe008
size    : 5

Один байт для самого объекта и 4 байта для счетчика, который хранится непосредственно перед выделенной областью объекта. Теперь, если мы используем функцию освобождения без параметра размера (просто удаляя его из оператора delete), мы получим следующий вывод:

sizeof f: 1
new    p: 0x9451008
new size: 1
&f_     : 0x9451008
delete p: 0x9451008

Среда выполнения C++ здесь не заботится о размере, поэтому она больше не хранит его. Обратите внимание, что это сильно зависит от реализации, и это то, что gcc делает здесь, чтобы иметь возможность определить размер в операторе-члене delete. Другие реализации могут по-прежнему хранить размер, и, скорее всего, будет, если есть деструктор для вызова класса. Например, просто добавив ~f() { } Выше gcc сохраняет размер независимо от того, какую функцию освобождения мы пишем.

Зависит от того, перегружен он или нет, если вы создали приложение для отладки, если вы используете детектор утечки памяти, если у вас есть какая-то схема пула памяти, если у вас есть что-то вроде сборщика мусора Boehm, который маркирует / отменяет маркировку битов и т. д. и т. д. Внутри может быть много нестандартных вещей или вообще ничего особенного.

Другие вопросы по тегам