复制构造函数中的段错误

时间:2012-11-01 19:12:43

标签: c++ class copy-constructor

我正在进行一项使用“Image”类操作* .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();
}

2 个答案:

答案 0 :(得分: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;
}

正如评论所暗示的那样,如果取消注释复制赋值运算符,整个过程就会起作用。

如果这是您的问题,请阅读“三条规则”(WikipediaWard's Wiki)。

答案 1 :(得分: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评论,所以你试图读取一个例如宽度。但这并不重要。如果您的代码可以创建垃圾对象,则可能会在尝试复制它们时崩溃。