C++ 复制构造函数中的Seg错误

C++ 复制构造函数中的Seg错误,c++,class,copy-constructor,C++,Class,Copy Constructor,我正在做一个作业,在作业中我们使用“Image”类处理*.ppm图像。当调用复制构造函数时,它编译并seg错误。这是: Image::Image(const Image & imageToCopy) { fileType = imageToCopy.fileType; width = imageToCopy.width; height = imageToCopy.height; maxColor = imageToCopy.maxColor; image = new int *[hei

我正在做一个作业,在作业中我们使用“Image”类处理*.ppm图像。当调用复制构造函数时,它编译并seg错误。这是:

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[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();
}
Image::Image(常量字符*文件名){
ifstream imageInputStream;
imageInputStream.open(文件名);
imageInputStream>>文件类型;
imageInputStream>>宽度;
imageInputStream>>高度;
imageInputStream>>maxColor;
图像=新整数*[高度];
对于(int i=0;i>图像[i][j];
}
}
imageInputStream.close();
}

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

<>你可能认为你在任何地方都没有做作业,但是除非你知道所有的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;
}
正如注释所暗示的,如果取消对复制赋值操作符的注释,整个过程都会正常工作


如果这是您的问题,请仔细阅读三(,)规则。

我获取了您粘贴在pastebin上的代码,并向两个构造函数添加了一些日志记录

Image(const char*)
中,在
imageInputStream>>maxColor
的后面:

    cout << "Image(" << filename << "): "
         << 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注释,所以您试图将其作为一个宽度来阅读。但这真的没关系。如果您的代码可以创建垃圾对象,那么在尝试复制它们时可能会崩溃。

要复制的图像的宽度和高度是多少?如果大小正常,并且您没有得到一个
std::bad\u alloc
,乍一看就可以了。我建议您使用std::vector,而不是C样式的数组。。。我强烈建议这样做。事实上,如果您将内容存储为
std::vector
,您可能甚至不需要复制构造函数……您能给我们一个最简单的完整示例吗?很可能你的
image1
格式不好。驯鹿间接地提出了一个好的观点:为什么宽度需要锯齿状(每行不同),假设图像的每一行的像素数可能与其他每一行的像素数相同……您能否在问题中添加
image
的声明……还有一个简单的问题:您是否有析构函数和赋值运算符?如果答案是“是”和“否”,您是否在做类似于
Image img2的事情;img2=img1任何地方?如果不使用赋值运算符,是否需要定义它。我知道,如果我像你在main中那样使用它,我需要它,但我不会对任何对象使用赋值。无论何时声明析构函数,都应该声明赋值运算符。否则,编译器将为您生成一个,这将是错误的。如果你确定你永远不会需要它,那么就声明它已被删除(C++11)或者声明它为私有,并且不定义它(C++03),但仍然声明它。(这样,如果你错了,你会得到一个编译器错误,而不是一个神秘的运行时崩溃。)好吧,瞧,让赋值操作符方法修复了它。我想这也会使很多复制构造函数代码过时,因为我可以创建一个新对象,并说image2=image1。谢谢,你可能想用另一个来定义一个。但最好的方法是另一种方法:定义
swap
方法,然后根据复制和交换定义赋值运算符。然后,您不需要编写任何代码来检查自赋值、删除旧值等。有关详细信息,请参阅。
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
P3
0 0
0