2014-10-29 9 views
5

Я знаю, что довольно много C++ часто задаваемых вопросов (и ответы здесь на SO) говорят, что нет необходимости проверять возвращаемое значение простого нового выражения для null, так как простое новое -expression указывает на сбои, бросая исключения. В основном они утверждают, что простое новое выражение никогда не возвращает null. (Под «простым новым выражением» я подразумеваю новое выражение, которое не является номером nothrow).Пользовательский оператор new, который возвращает нулевой указатель

Однако, несмотря на это, это очень простой вопрос, я вдруг понял, что не понимаю, какие конкретные предположения они делают (если они есть), когда они дают ответ.

В частности, я задаюсь вопросом, могу ли я перегрузить базовую формуляр ::operator new, чтобы всегда возвращать нулевой указатель и, следовательно, ожидать, что все простые новые выражения, которые используют этот оператор, также вернут нулевые указатели.

В соответствии с языковой спецификацией, если мой ::operator new объявлен как неброска, я могу/должен указывать на отказ выделения памяти, возвращая нулевой указатель. Итак, давайте просто

void *operator new(size_t s) throw() { 
    return 0; 
} 

int main() { 
    int *i = new int; 
} 

В моих экспериментах над новым выражением не успешно возвращает нулевой указатель. Итак, я нарушаю какие-либо правила в приведенном выше коде или нет? Является ли законным объявлять простой ::operator new как не метательный?

А если приведенный выше код в порядке, то я предполагаю, что когда кто-то заявляет, что простой новый «никогда не возвращает нулевой указатель», они делают это в предположении, что версия ::operator new, предоставленная стандартной библиотекой, не была заменены. Правильно ли это презумпция?

+0

Есть еще один аспект этого обсуждения - даже если стандарт явно разрешает вам возвращать 'nullptr' /' 0', как вы сказали, это стандартные библиотеки, необходимые для обработки '0' s? Я бы поспорил, что это не так, а реализации нет, поэтому было бы непрактичным писать программу с возвратом 0. :: operator new. 20.8.9.1/4 требует 'std :: allocate :: allocate' throw' std :: bad_alloc', если невозможно получить хранилище - будет ли он (как правило, избыточно) проверять значение null или доверять ':: operator new' для броска? –

+0

Не нужна ли другая версия, не имеющая метательных версий, новая? 'void * operator new (std :: size_t size);' не может возвращать нулевой указатель, он должен бросать в случае ошибки, даже если он переопределен. – user657267

+0

Стандартная библиотека будет использовать ':: new T' для стандартной конструкции и' :: new (static_cast (get_allocator() (1)) T' для размещения, и эти формы всегда вызывают функцию выделения метаданных (независимо от того, был заменен). –

ответ

1

Операторы можно заменить следующим образом

[replacement.functions]

(2.1) — operator new(std::size_t) 
(2.2) — operator new(std::size_t, const std::nothrow_t&) 
(2.3) — operator new[](std::size_t) 
(2.4) — operator new[](std::size_t, const std::nothrow_t&) 
(2.5) — operator delete(void*) 
(2.6) — operator delete(void*, const std::nothrow_t&) 

void *operator new(size_t s) throw() является недействительным, он имеет бросить в случае ошибки

[new.delete .single]

void* operator new(std::size_t size); 

3 Обязательное поведение: Верните a указатель нумерации, чтобы соответствующим образом выровнять хранилище (3.7.4), либо выбросить исключение bad_alloc. Это требование является обязательным для замены версии этой функции.

Однако вы можете смело заменить без метательных noexcept перегрузок с функцией, которая всегда возвращает нуль, а тот, кто называет эти перегрузки должны быть осведомлены об этом поведении и проверить возвращаемое значение, соответственно. Очевидно, что они не будут вызываться, если не будет принят nothrow тег, т.е. int* i = new (std::nothrow) int;

void* operator new(std::size_t size, const std::nothrow_t&) noexcept; 

7 Требуемое поведение: Возвращает ненулевое указатель соответствующим образом выровнены хранения (3.7.4), либо возвращают null указатель. Эта ночная версия из operator new возвращает указатель, полученный как полученное из обычной версии (возможно, замененной).Это требование является обязательным для замены этой функции .