Как проверить ошибки выделения памяти с новым оператором?
Совсем недавно я переключил язык моего проекта на использование C++ с C. В C я использовал malloc, и после этого я проверял, был ли malloc успешным, но в C++ я использую "new" для выделения памяти и хотел бы узнать, как вы обычно проверяет сбой выделения памяти.
Из моего поиска в Google я увидел nothrow как следующее.
char *buf = new (nothrow)char[10];
Я также видел следующее.
try{} catch(bad_alloc&) {}
Но как насчет следующего? Я использую некоторые подпрограммы библиотеки Chrome для использования умных указателей.
Например, у меня есть следующий код.
scoped_array<char> buf(new char[MAX_BUF]);
Здорово использовать умные указатели, но я просто не уверен, как мне проверить, было ли выделение памяти успешным. Нужно ли разбивать на два отдельных оператора с помощью nothrow или try/catch? Как вы обычно делаете эти проверки в C++?
Любой совет будет оценен.
4 ответа
Ну, вы называете новым, который бросает 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
}
Под моим ответом я подразумеваю, что умные указатели распространяют исключения. Поэтому, если вы выделяете память обычным броском new, вы должны поймать исключение. Если вы выделяете с помощью nothrow new, то вы должны проверить nullptr
, В любом случае, умные указатели ничего не добавляют к этой логике
Ненавижу это говорить, но ИМО, вы идете в неправильном направлении (и, к сожалению, другие ответы, которые вы получили, тоже не указали вам правильное направление).
Вместо того, чтобы выбирать между различными вариантами умного указателя и / или обычными вариантами new
Вы, вероятно, должны сделать еще как минимум два шага назад от того, что делаете, и заменить вручную управляемые динамические структуры данных коллекциями. Это не всегда может быть правильным выбором, но, по моему опыту, это правильный путь гораздо чаще, чем нет. Стандартная библиотека имеет ряд возможностей (vector, deque, list, set и т. Д.), И очень велики шансы, что вы можете использовать одну из них, а не иметь дело непосредственно с new
и компания на всех.
По умолчанию они будут использовать распределитель, который в конечном итоге использует обычный (бросающий) вариант new
, Поэтому вы обычно хотите поместить большую часть кода в try
блок на довольно высоком уровне, и имеют catch
пункт, который имеет дело с нехваткой памяти там.
Когда / если вам нужно иметь дело с выделением памяти напрямую, вполне вероятно, что вы все равно захотите предоставить интерфейс, аналогичный интерфейсу стандартных контейнеров в библиотеке, чтобы он работал с обычными алгоритмами и итераторами. Ваш первоначальный опыт использования существующих контейнеров окупится, когда вы доберетесь до этой точки, даже если это может быть способом в будущем.
В C++ есть 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
}
Мне любопытно, что вы ожидаете делать в случае неудачного распределения? Если для выделения вашего объекта не хватает памяти, часто очень мало что можно сделать в процессе.
Вам все равно нужно будет проверить наличие ошибки выделения памяти.
Или
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
}