Как проверить ошибки выделения памяти с новым оператором? - PullRequest
26 голосов
/ 26 июля 2011

Совсем недавно я переключил язык моего проекта на использование 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 ]

20 голосов
/ 26 июля 2011

Ну, вы называете new, который выбрасывает 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. В любом случае, умные указатели ничего не добавляют к этой логике

16 голосов
/ 26 июля 2011

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

Вместо того, чтобы выбирать между различными вариантами умного указателя и / или обычного или ненурового вариантов new, вы должны , вероятно, сделать еще как минимум два шага назад от того, что вы делаете, и заменить ваши управляемые вручную динамические структуры данных с коллекциями. Это не может всегда быть правильным выбором, но по крайней мере, по моему опыту, это правильный путь к лоту чаще, чем нет. Стандартная библиотека имеет ряд возможностей (vector, deque, list, set и т. Д.), И вполне вероятно, что вы можете использовать одну из них, вместо того, чтобы напрямую иметь дело с new и компанией.

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

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

6 голосов
/ 26 июля 2011

В 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
}

Мне любопытно, что вы ожидаете делать в случае неудачного распределения? Если для выделения вашего объекта не хватает памяти, часто очень мало что можно сделать в процессе.

1 голос
/ 26 июля 2011

Вам все равно нужно будет проверить наличие ошибки выделения памяти.

Либо

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
}
...