Как использовать std::nothrow и std::new_handler в стандартном заголовочном файле <new>

Наткнулся на небольшой стандартный заголовочный файл <new>, Я, вероятно, не видел его прямого использования раньше. Вот версия g++ для тех, кому интересно.

Ниже часть моего интереса:

  struct nothrow_t { };
  extern const nothrow_t nothrow;
  /** If you write your own error handler to be called by @c new, it must
   *  be of this type.  */
  typedef void (*new_handler)();
  /// Takes a replacement handler as the argument, returns the previous handler.
  new_handler set_new_handler(new_handler) throw();
  1. Как struct nothrow_t и его объект nothrow используются программистами? Действительно ли объект должен быть extern?
  2. Когда делает new_handler используемый?
  3. Почему все operator new/delete объявлены в extern C++ блок?

2 ответа

Решение

nothrow_t используется, чтобы сказать operator new работать в обратно совместимом режиме "вернуть ноль при ошибке, а не выдавать исключение".

То есть, если вы видите такой код:

int * idx = new(std::nothrow) int;

это было бы nothrow_t на работе. Для соответствующих разделов в стандарте начните с (по состоянию на C++11 N3376) 17.6.4.6 [replace.functions]/1 и продвигайтесь вниз оттуда.

Чтобы ответить на ваши конкретные вопросы:

  1. Да, он действительно должен быть внешним, по крайней мере, в соответствии с 18.6 [support.dynamic]/1, который включает в себя:

    namespace std {
        class bad_alloc;
        class bad_array_new_length;
        struct nothrow_t {};
        extern const nothrow_t nothrow;
        typedef void (*new_handler)();
        new_handler get_new_handler() noexcept;
        new_handler set_new_handler(new_handler new_p) noexcept;
    }
    

    Кроме того, в 17.6.2.3 [using.linkage]/1 сказано, что "объекты в стандартной библиотеке C++ имеют внешнюю связь (3.5)". Функции и классы (например, get_new_handler а также set_new_handler выше) явно не нужно аннотировать, чтобы иметь внешнюю связь, потому что они имеют внешнюю связь по умолчанию.

  2. new_handler используется, когда пользователь переопределяет значение по умолчанию operator new используется по телефону set_new_handler, Это просто тип указателя на функцию.

  3. Вероятно, потому что подписи для operator new не зарезервированы в C. extern "C++" сообщает компилятору, что им разрешено выполнять манипулирование именами и другие специфические для C++ функции для этих функций. Таким образом, вы можете скомпилировать один модуль перевода как C, а другой как C++, и связать их вместе в одном двоичном файле, не беспокоясь о том, что кто-то в C определил функцию, конфликтующую с компилятором. operator new,

Ну, это действительно вопрос "прочитай документацию, пожалуйста". Любая хорошая вводная книга по C++ должна обсуждаться nothrow, Например, "язык программирования C++" Бьярне, как я помню, делает.

Но в любом случае вы используете nothrow превратить std::bad_alloc исключения в результатах нулевого указателя, и вы используете новый обработчик для повторной попытки неудачного размещения.

На практике не забудьте поставить :: перед new когда вы используете nothrow и вообще при использовании глобального размещения новых, чтобы избежать подбора новых мест размещения из классов. За исключением того, что в целом следует избегать размещения новых (как это и есть очень низкоуровневая функция языка), я бы сделал это, даже если это технически не имеет смысла. Так же, как хорошая привычка.


Пример:

#include <iostream>     // std::wcout, std::endl
#include <stdlib.h>     // EXIT_FAILURE, EXIT_SUCCESS
#include <new>          // std::nothrow
using namespace std;

int main()
{
    int* const p = ::new( std::nothrow ) int[0x7fffffff/sizeof(int)];
    if( !p )
    {
        cout << "Allocation failed!" << endl;
        return EXIT_FAILURE;
    }
    cout << "Alles success!" << endl;
    delete[] p;
    return EXIT_SUCCESS;
}

Вывод на мою систему:

[D: \ DEV \ тест]
> а
Распределение не удалось!

[D:\ DEV \ тест]
> _

Обратите внимание, что вышеприведенное предполагает 32-битный процесс:)

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