Image 类的析构函数和重载 = 运算符

Posted

技术标签:

【中文标题】Image 类的析构函数和重载 = 运算符【英文标题】:Destructor and overloaded= operator for Image class 【发布时间】:2014-12-08 19:18:33 【问题描述】:

我是 C++ 新手。我有图像处理的问题。我要做的是编写我的类 Image,它具有图像的水平和垂直大小以及每个像素的数据(灰度,只是 2D 浮点数组)作为私有变量。我还在类中编写了基本函数:getPixel、SetPixel、GetSize、GetData(返回二维数据数组)。

我的问题是:我读到,为了获得最佳性能,我必须编写一个析构函数并至少重载“=”运算符。

1)有人可以解释为什么我真的需要它(只要这个版本或多或少地工作)。

2) 你能帮我写析构函数和“=”操作符吗?我想,这对专家来说并不难,我试过一次,但我的析构函数出现了内存错误:Error _BLOCK_TYPE_IS_VALID(pHead->nBlockUse);

更新:即使是现在,不用定义“=”运算符,我也可以在我的主函数中使用它。例如,如果我有大小为 (1x1) 的 Image img1 和大小为 (2x2) 的 img2,我可以写 img1=img2,它可以工作!

Update2:在我尝试实现简单的析构函数(delete [] pix)后,出现错误“_BLOCK_TYPE_IS_VALID”

struct Pixel

    float p;
;
struct size

    int x;
    int y;
;
class Image 
private:
   int _x, _y;
   Pixel *pix;
public:
    Image(int x, int y)
        pix = new Pixel[x * y];
        _x = x;
        _y = y;
    
    float getPixel(int i, int j) 
        return pix[i * _y + j].p;
    
    void setPixel(int i, int j, Pixel val)
    
        pix[i * _y + j].p = val.p;
    
    size GetSize()
        size a;
        a.x = _x;
        a.y = _y;
        return a;
    

    Pixel **GetData()
        Pixel **a=0;
        a = new Pixel*[_x];
        for (int i = 0; i < _x; i++)
            a[i] = new Pixel[_y];
            for (int j = 0; j < _y; j++)
                a[i][j] = pix[i*_y + j];
            
        
        return a;
    
;

UPDDATE 3:我尝试实现三规则中的所有内容。我补充说:

~Image()

    delete[] pix;


Image(const Image& that)

    pix = new Pixel[that._x*that._y];
    pix = that.pix;
    _x = that._x;
    _y = that._y;

Image& operator=(const Image& that)

    if (this != &that)
    
        delete[] pix;
        pix = new Pixel[that._x*that._y];
        pix = that.pix;
        _x = that._x;
        _y = that._y;
    
    return *this;

仍然出现内存错误:“_BLOCK_TYPE_IS_VALID...”

【问题讨论】:

使用std::vector&lt;Pixel&gt; 而不是Pixel* 代替pix,你也不必写。 但这有效。为什么vector更好? 因为std::vector会为你管理内存,你不必担心删除它、调整它的大小、复制时分配新的缓冲区等等。 【参考方案1】:

你问:

1) 谁能解释我为什么真的需要它(只要这个版本或多或少地工作)。

您在构造函数中为pix 分配内存。您需要实现一个析构函数来释放内存。我没有看到在你的课堂上实现了。

~Image()

   delete [] pix;

只要您在析构函数中添加代码以释放类在其生命周期的某个时间点获取的资源,The Rule of Three 就会发挥作用,您必须实现复制构造函数和赋值运算符无错误代码。

赋值运算符看起来像:

Image& operator=(Image const& rhs) 
    // Don't do anything for self assignment, such as a = a;
    if ( this != &rhs )
    
       delete [] pix;
       _x = rhs._x;
       _y = rhs._y;

       pix = new Pixel[_x * _y];
       for ( int i = 0; i < _x*_y; ++i )
       
          pix[i] = rhs.pix[i]
       
    
    return *this;

【讨论】:

插入你的析构函数后,错误“_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)”又出现了。 您还需要实现复制构造函数。不确定您是否这样做。 我尝试按照三规则来实现所有内容。还是报错。我在我的问题的更新 3 中写了它。 复制构造函数中pix = that.pix; 行错误。您需要从that.pix 复制值,就像我在operator= 函数中显示的那样。只需将rhs 替换为that【参考方案2】:

1) 谁能解释我为什么真的需要它(只要这个版本或多或少地工作)。

这里已经回答了:https://***.com/a/4172724/2642059 与您相关的部分是:

大多数时候,您不需要自己管理资源,因为诸如 std::string 之类的现有类已经为您完成了。只需将使用 std::string 成员的简单代码与使用 char* 的复杂且容易出错的替代代码进行比较,您就会被说服。 只要您远离原始指针成员,三法则就不太可能涉及您自己的代码。

作为一个新的 C++ 程序员,我能为你做的最好的事情就是让你远离原始指针。

2) 你能帮我写析构函数和“=”操作符吗?我想,这对专家来说并不难,我试过一次,但我的析构函数出现了内存错误:Error _BLOCK_TYPE_IS_VALID(pHead->nBlockUse);

R Sahu 的回答在这方面做得很好。但我建议您改用原始指针,因此我将向您展示如何做到这一点:

struct Pixel

    Pixel() : p(0.0f)  // Create a default constructor for Pixel so it can be used in a vector
    float p;
;

class Image 
private:
   int _x, _y;
   std::vector<Pixel> pix; // This is your new array
public:
    Image(int x, int y) :
        pix(x * y) // This is called the constructor initializer list and that's where you construct member objects.
    
        _x = x;
        _y = y;
    
    float getPixel(int i, int j) 
        return pix[i * _y + j].p;
    
    void setPixel(int i, int j, Pixel val)
    
        pix[i * _y + j].p = val.p;
    
    size GetSize()
        size a;
        a.x = _x;
        a.y = _y;
        return a;
    

    const Pixel* GetData() // We're going to pass back the vector's internal array here, but you should probably just return a const vector
        return pix.data(); // We're returning this as read only data for convenience any modification to the data should be done through the Image class
    
;

【讨论】:

谢谢!我现在就试试。我尝试按照规则三编写析构函数、复制和赋值运算符,但仍然出现此错误。 这行得通!但是这里的 GetData() 函数应该返回二维数组...但是很容易编辑。 Pixel** 不是二维数组,它是指向指针的指针,或者如果它“指向数组”,则指向指针数组的第一个元素.从Pixel* 转换为Pixel** 将导致未定义的行为。 @МихаилМихайловичГенкин 好吧,如果你认为它“易于编辑”,我很害怕。我建议您查看一些有关将一维数组索引为二维数组的 ***s 其他问题,如果它们不清楚,也许您可​​以提出一个新问题?

以上是关于Image 类的析构函数和重载 = 运算符的主要内容,如果未能解决你的问题,请参考以下文章

C++虚析构函数

4.1.7 特殊方法与运算符重载

mfc 类的析构函数

虚析构函数

基类的析构函数写成virtual虚析构函数

C++ 设置基类的析构函数为虚函数