Что мне делать, если конструктору не удается выделить память в C ++? - PullRequest
4 голосов
/ 05 июля 2010

Я только что столкнулся с проблемой, когда конструктор класса должен выделить память.Поэтому я радостно написал char *mem = static_cast<char*>(malloc(100*sizeof(*mem)));.Но потом я вдруг понял, что в случае ошибки я не могу вернуть код ошибки (я не использую исключения в своем коде).Как я могу решить эту проблему?

Должен ли я добавить члена bool initialized, а затем после занятий и проверить его сразу после, как в:.

Ответы [ 4 ]

9 голосов
/ 05 июля 2010

Вы должны использовать новый, а не malloc. new выдает std :: bad_alloc, когда у вас недостаточно памяти. Исключение следует распространять из конструктора, если вы не можете выделить его (или по какой-либо другой причине возникли проблемы с инициализацией), поскольку это единственный способ предотвратить вызов деструктора. Если конструктор успешно завершает работу, деструктор должен быть вызван (если, конечно, он не был выделен в куче и никогда не освобождался).

5 голосов
/ 05 июля 2010

Вот для чего были придуманы исключения. Также используйте new вместо malloc(3).

3 голосов
/ 05 июля 2010

Если вы не используете исключения, вы не должны использовать конструкторы (или не должны писать конструкторы, которые могут потерпеть неудачу), потому что, как вы заметили, нет способа сообщить об ошибке из конструктора, кроме как через исключение. Вы можете поочередно использовать заводскую функцию и использовать ее для отделения битов, которые могут выйти из строя, от битов, которые не могут

class myClass {
  private:
  char *m_malloced_buffer;

  // disallow calling ctors/dtors directly
  myClass(char *malloced_buffer) : m_malloced_buffer(malloced_buffer) {}
  ~myClass() { free(m_malloced_buffer); }

  public:
  static myClass *create()
  {
     char *buf = static_cast<char*>(malloc(100*sizeof(*mem)));
     if(!buf) return NULL;

     void *myClassRes = malloc(sizeof(myClass));
     if(!myClassRes) return NULL;
     new (myClassRes) myClass(buf); // placement new, uses existing memory to invoke the ctor
     return static_cast<myClass*>(myClassRes);
  }
  static void destroy(myClass* val)
  {
     if(!val) return;
     val->~myClass(); // explicitly invoke dtor
     free(val); // deallocate memory
  }
};
...
myClass *val = myClass::create();
if(val) { ... }
myClass::destroy(val);

В этом примере я использовал malloc и free, чтобы сделать все выделение, вы можете использовать new (std :: nothrow) и удалить так же легко. Вам нужно будет извлечь каждую операцию, которая может завершиться с ошибкой, из вашего ctor-компонента в заводскую функцию, чтобы вы могли проверять ошибки без использования исключений. Даже в этом простом примере вы можете видеть, что это огромная боль в шее. Вы говорите, что узнали, что «исключения не являются хорошим стилем кодирования» в комментарии, вы имеете в виду, что вы узнали что (будь то по инструкции с аргументированными аргументами и объяснениями или из опыта) или кто-то сказал, что «исключения не хороший стиль кодирования ", и вы приняли заявление как догму?

Использование инициализированного члена bool приводит к проблеме с объектом-зомби (см. http://www.parashift.com/c++-faq-lite/exceptions.html).

2 голосов
/ 05 июля 2010

Если вы используете C ++, а не C, вы, вероятно, должны использовать new вместо malloc. Создание исключения - это, вероятно, то, что вы хотите сделать из конструктора.

Если вы используете new (nothrow), хотя, поскольку вы не хотите исключение, или вы используете malloc, вы можете просто проверить указатель, возвращаемый для NULL. Затем вы должны установить переменную-член, которая указывает, что объект находится в состоянии сбоя. Это видно в потоковых классах стандартной библиотеки C ++.

...