从构造函数中调用构造函数

时间:2011-09-18 19:18:45

标签: c++ inheritance constructor

在下面的代码中,我遇到了一个问题。它表现为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 个答案:

答案 0 :(得分:3)

您的代码违反了一条非常重要的规则,即“三巨头”

  

如果您的班级有任何的析构函数,赋值运算符或副本   构造函数然后它应该所有三个

原因是如果存在自定义析构函数,那么很可能自动合成的赋值运算符和复制构造函数(只是逐个成员的复制结构或赋值)是不正确的。< / p>

这个规则非常重要,如果您碰巧找到一个案例,其中有一个例子是析构函数但是默认的复制构造函数,那么至少在注释中写一下你没有忘记复制构造函数和/或任务,但自动提供的将是正确的。

如果您的类不能被复制或复制构造,那么通过声明它是私有的并且不写入实现来禁止该操作。

在特定情况下,当复制或分配两个类中的任何一个的实例时,将复制指针,但数据将被销毁两次。

答案 1 :(得分:2)

我没有看到使用构造函数的方式存在问题,这会导致bad_alloc(尽管代码看起来很笨拙)。让我们看看导致问题的行的执行 -

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

执行以下步骤:

  1. 创建了时间FileReader。它的构造函数使用filename调用,它是const char*
  2. 构造函数做了未知的事情,因为我们没有它的代码。我认为应该将文件读入已分配的缓冲区,该缓冲区存储在data的{​​{1}}成员中。
  3. 在临时FileReader上调用
  4. getFileData(),返回FileReader的值,我认为这是data
  5. unsigned char *是一个reader,是使用CompressedBufferReader构建的。
  6. 时间unsigned char *被破坏。
  7. 因此,问题不在于构造的顺序,也不在于临时FileReader的生命周期。你应该研究一些未知的事情:

    1. FileReader的构造函数是否创建了有效的缓冲区,并将其存储在FileReader
    2. data是否返回创建的缓冲区?
    3. getFileData()是否为有效缓冲区返回正确的值?
    4. 异常是否从GetDecompressedBufferSize()抛出,我们的代码没有?{/ li>

      最后,您可能希望简化代码。像这样的结构不是很易读。当然,使用像矢量这样的标准容器会使它更安全。