2

我正在处理一项使用“图像”类操作 *.ppm 图像的任务。当调用复制构造函数时,它会编译然后段错误。这里是:

Image::Image(const Image & imageToCopy) {
fileType = imageToCopy.fileType;
width = imageToCopy.width;
height = imageToCopy.height;
maxColor = imageToCopy.maxColor;

image = new int *[height];

for(int i=0; i < height; i++) {
    image[i] = new int [width];
    for(int j=0; j < width; j++) {
    image[i][j] = imageToCopy.image[i][j];
    }
}
}

像这样调用:

Image image2(image1);

我对为什么会发生这种情况感到有些不知所措。我不知道出了什么问题,因为代码几乎与我的构造函数相同,可以正常工作。唯一的区别是我有

image[i][j] = imageToCopy.image[i][j];

代替

imageInputStream >> image[i][j];

想法?谢谢

编辑:构造函数如下:

Image::Image(const char* filename) {
    ifstream imageInputStream;
    imageInputStream.open(filename);

    imageInputStream >> fileType;
    imageInputStream >> width;
    imageInputStream >> height;
    imageInputStream >> maxColor;

    image = new int *[height];

    for(int i=0; i < height; i++) {
        image[i] = new int [width];
        for(int j=0; j < width; j++) {
            imageInputStream >> image[i][j];
        }
    }

    imageInputStream.close();
}
4

2 回答 2

3

没有看到完整的代码,这只是一个猜测,但是如果您创建了一个复制构造函数和一个析构函数但没有复制赋值运算符,那么如果您尝试使用赋值,您可能会遇到与此完全相同的段错误。

而且您可能不会认为自己在任何地方做作业,但除非您了解 C++ 的所有规则(即使是专家也不知道,更不用说新学生了),否则很难确定。最简单的找出方法是声明一个私有赋值运算符并且不定义它(或者,如果您使用 C++11,则声明它已删除)并查看是否出现编译错误。

例如:

struct Image {
  int width_, height_;
  int **image_;
  Image(int width, int height) : width_(width), height_(height),
                                 image_(0) {
    image_ = new int *[height_];
    for (int i = 0; i != height_; ++i) {
      image_[i] = new int[width_];
      for (int j = 0; j != width_; ++j) {
        image_[i][j] = 1;
      }
    }
  }

  Image(const Image& rhs) : width_(rhs.width_), height_(rhs.height_),
                            image_(0) {
    image_ = new int*[height_];
    for (int i = 0; i != height_; ++i) {
      image_[i] = new int[width_];
      for (int j = 0; j != width_; ++j) {
        image_[i][j] = rhs.image_[i][j];
      }
    }
  }

  /* uncomment to uncrash
  Image& operator=(const Image& rhs) {
    if (this == &rhs) return *this;
    for (int i = 0; i != height_; ++i) {
      delete [] image_[i];
    }
    delete [] image_;
    image_ = new int*[height_];
    for (int i = 0; i != height_; ++i) {
      image_[i] = new int[width_];
      for (int j = 0; j != width_; ++j) {
        image_[i][j] = rhs.image_[i][j];
      }
    }
    return *this;
  }
  */

  ~Image() {
    for (int i = 0; i != height_; ++i) {
      delete [] image_[i];
    }
    delete [] image_;
  }
};

int main(int, char*[]) {
  Image img(200, 300);
  Image img2(img);
  Image img3(100, 200);
  img3 = img2;
  return 0;
}

正如评论所暗示的,如果您取消对复制赋值运算符的注释,则整个操作都有效。

如果这是您的问题,请阅读三法则(维基百科沃德的维基)。

于 2012-11-01T19:45:47.073 回答
0

我使用了您在 pastebin 中粘贴的代码,并向两个构造函数添加了一些日志记录。

Image(const char *), 之后imageInputStream >> maxColor;:

    cout << "Image(" << filename << "): "
         << fileType << ", "
         << width << ", "
         << height << ", "
         << maxColor << endl;

Image(const Image&), 之后maxColor = imageToCopy.maxColor;:

    cout << "Image(Image): "
         << fileType << ", "
         << width << ", "
         << height << ", "
         << maxColor << endl;

这是输出:

Testing standard constructor, opening tux.ppm
Image(tux.ppm): P3, 0, 0, 0
Calling flip method
Calling dither method
Saving the flipped and dithered image
Creating a 2nd image object, using tux.ppm again with the standard constructor
Image(tux.ppm): P3, 32767, 1656563112, 17

换句话说,你正在阅读垃圾。第一次通过时,我碰巧读取了 0x0 并返回了一个空图像。然后我读了 32767x1656563112 并创建了一个巨大的垃圾图像,这需要很长时间,我不想等待,但我可以想象复制它会出现段错误。

为了验证是否是这种情况,请查看输出为 tux_transformed.ppm 的内容:

P3
0 0
0

当然,我没有你的 tux.ppm 文件,但是我从不同的来源向它扔了一堆示例 PPM,它们都有同样的问题。

作为一个疯狂的猜测,您的问题是您没有处理 PPM 注释,因此您试图将其读取为例如宽度。但这真的没关系。如果您的代码可以创建垃圾对象,则尝试复制它们可能会崩溃。

于 2012-11-01T20:11:24.850 回答