Вызов конструкторов из конструкторов - PullRequest
2 голосов
/ 18 сентября 2011

В этом коде, который я представляю ниже, у меня возникла проблема.Это проявляется как исключение bad_alloc, и это потому, что аргумент, переданный reader, CompressedBufferReader, является неверной строкой.

class FileReader { 
    FILE *file; 
protected:
    unsigned char *data; // local copy
    long size;
public:
    FileReader(const char *filename);
    ~FileReader();
    unsigned long getSize();
    unsigned char *getFileData();
};

class CompressedBufferReader {
    unsigned char *buffer;
    unsigned long len;
public:
    CompressedBufferReader(unsigned char *);
    ~CompressedBufferReader();
    unsigned char *getBuffer();
    unsigned long getLength();
};
CompressedBufferReader::CompressedBufferReader(unsigned char *srcCompressed) {
    len = 0; buffer = 0;
    len = GetDecompressedBufferSize(srcCompressed);
    buffer = new unsigned char[len]; if (!buffer) throw std::runtime_error("Cannot allocate!");
    WriteDecompressedBuffer(buffer, len, srcCompressed);
}
CompressedBufferReader::~CompressedBufferReader() {
    delete[] buffer;
}
unsigned char *CompressedBufferReader::getBuffer() {return buffer;}
unsigned long CompressedBufferReader::getLength() {return len;}

// similar interface to FileReader. Does not inherit because it does not benefit from doing so.
class CompressedFileReader {
    CompressedBufferReader reader;
public:
    CompressedFileReader(const char *filename);
    unsigned char *getFileData();
    unsigned long getSize();
};

CompressedFileReader::CompressedFileReader(const char *filename) : reader(FileReader(filename).getFileData()){} // this line is causing the problem
unsigned char *CompressedFileReader::getFileData() { return reader.getBuffer(); }
unsigned long CompressedFileReader::getSize() { return reader.getLength(); }

Точнее говоря, создается впечатление, что FileReader, который я создаю анонимно, освобождается до того, как его содержимое данных может быть передано в конструктор reader, CompressedBufferReader.

проблема в том, что я не могу написать конструктор CompressedFileReader так, чтобы я мог правильно создать экземпляр FileReader, потому что я намереваюсь использовать конструктор CompressedBufferReader, а это значит, что я должен вызватьэто перед телом конструктора.Немного подвоха-22.Как решается эта проблема?

Ответы [ 2 ]

3 голосов
/ 18 сентября 2011

Ваш код нарушает очень важное правило, известное как "большая тройка"

Если в вашем классе есть любой деструктора, оператора присваивания или конструктора копирования, тогда ондолжно иметь все три из них .

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

Это правило настолько важно, что если вам случится найти случай, в котором имеет смысл иметь, например, деструктор, но по умолчаниюзатем просто напишите конструктор копирования, по крайней мере, в комментарии, который вы не забыли о конструкторе копирования и / или назначении, но что автоматически предоставленный будет правильным.

Если вместо этого ваши классы не должны копироваться илисоздайте копию, а затем запретите операцию, объявив ее закрытой и не записавion.

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

2 голосов
/ 19 сентября 2011

Я не вижу проблемы в том, как вы используете конструкторы, что должно вызывать bad_alloc (хотя код кажется неуклюжим). Давайте посмотрим на выполнение строки, которая вызывает проблему -

CompressedFileReader::CompressedFileReader(const char *filename) : 
   reader(FileReader(filename).getFileData()){}

Выполняются следующие шаги:

  1. Временная FileReader создана. Его конструктор вызывается с filename, который является const char*.
  2. Конструктор делает неизвестные вещи, потому что у нас нет его кода. Предполагается, что он должен прочитать файл в выделенном буфере, хранящемся в элементе data элемента FileReader.
  3. getFileData() вызывается по температуре FileReader, возвращая значение data, я полагаю, что является unsigned char *.
  4. reader, который является CompressedBufferReader, построен с использованием unsigned char *.
  5. Временное FileReader разрушено.

Итак, проблема не в порядке конструкций или в сроке службы временного FileReader. Есть несколько неизвестных, которые вы должны посмотреть:

  1. Создает ли конструктор FileReader допустимый буфер и сохраняет его в data?
  2. Возвращает ли getFileData() созданный буфер?
  3. Возвращает ли GetDecompressedBufferSize() правильное значение для допустимого буфера?
  4. Бывает ли исключение из WriteDecompressedBuffer, чей код у нас нет?

Наконец, вы можете упростить свой код. Подобные конструкции не очень читабельны. И, конечно же, использование стандартных контейнеров, таких как векторы, сделает его более безопасным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...