Как проверить сбои распределения памяти с новым оператором?
Совсем недавно я переключил язык моего проекта на использование С++ из C.
С C я использовал malloc, и после этого я проверяю, был ли malloc успешным, но с С++ я использую "новый" для выделения памяти, и я хотел бы знать, как вы обычно проверяете отказ в распределении памяти.
Из моего поиска в Google я увидел nothrow, как показано ниже.
char *buf = new (nothrow)char[10];
Я также видел следующее.
try{} catch(bad_alloc&) {}
Но как насчет следующего? Я использую некоторые из процедур библиотеки chrome для использования интеллектуальных указателей.
Например, у меня есть код следующим образом.
scoped_array<char> buf(new char[MAX_BUF]);
Замечательно использовать интеллектуальные указатели, но я просто не уверен, как проверить, успешно ли выделено выделение памяти.
Нужно ли мне разбивать на два отдельных заявления с помощью nothrow или try/catch?
Как вы обычно делаете эти проверки на С++?
Любые советы будут оценены.
Ответы
Ответ 1
Ну, вы вызываете новое, которое бросает bad_alloc
, поэтому вы должны его поймать:
try
{
scoped_array<char> buf(new char[MAX_BUF]);
...
}
catch(std::bad_alloc&)
{
...
}
или
scoped_array<char> buf(new(nothrow) char[MAX_BUF]);
if(!buf)
{
//allocation failed
}
Я имею в виду, по моему мнению, что интеллектуальные указатели распространяют исключения. Поэтому, если вы выделяете память обычным бросанием нового, вы должны поймать исключение. Если вы назначаете nothrow new, то вы должны проверить nullptr
. В любом случае интеллектуальные указатели ничего не добавляют к этой логике
Ответ 2
Я ненавижу это говорить, но IMO, вы идете в неправильном направлении (и, к сожалению, другие ответы, которые вы получили, на самом деле не указали вам в правильном направлении).
Вместо того, чтобы выбирать между различными вариантами интеллектуального указателя и/или нормального варианта vs nothrow new
, вам, вероятно, потребуется, по крайней мере, еще два шага назад от того, что вы делаете, и заменить динамические данные, управляемые вручную структуры с коллекциями. Это не всегда может быть правильным выбором, но, по крайней мере, по моему опыту, это правильный путь гораздо чаще, чем нет. Стандартная библиотека имеет ряд возможностей (вектор, дека, список, набор и т.д.), И есть неплохие шансы, что вы можете использовать один из них, а не напрямую обращаться с new
и компанией.
По умолчанию они будут использовать распределитель, который заканчивает использование обычного (метательного) варианта new
. Поэтому вы обычно хотите разместить большинство кода в блоке try
на довольно высоком уровне и иметь предложение catch
, которое имеет дело с тем, что там не хватает памяти.
Когда/если вам нужно иметь дело с распределением памяти напрямую, вероятность того, что вы все еще хотите предоставить интерфейс, аналогичный интерфейсу стандартных контейнеров в библиотеке, будет работать с обычными алгоритмами и итераторами. Ваш первоначальный опыт использования существующих контейнеров будет хорошо пополняться, когда вы доберетесь до этого момента, хотя это может быть путь по дороге.
Ответ 3
В С++ существует 2 основных способа, в которых new
выделяет память, и для каждой из них требуется различная проверка ошибок.
Стандартный new
оператор бросает исключение std::bad_alloc
при сбое, и это можно обрабатывать как обычное исключение
try {
char* c = new char[100];
} catch (std::bad_alloc&) {
// Handle error
}
Или альтернатива nothrow
версия new
просто вернет NULL
при ошибке
char* c = new (std::nothrow) char[100];
if (!c) {
// Handle error
}
Мне любопытно, что вы планируете делать, когда распределение не удается? Если для размещения объекта нет памяти, часто бывает очень мало, что можно сделать в этом процессе.
Ответ 4
Вам по-прежнему необходимо проверить наличие сбоя в распределении памяти.
Либо
scoped_array<char> buf;
try {
buf.reset( new char[MAX_BUF] );
} catch( std::bad_alloc& ) {
// Handle the failure
}
или
scoped_array<char> buf( new(std::nothrow)char[MAX_BUF] );
if( buf.get() == NULL ) {
// Handle the failure
}