【问题标题】:Reseting object m_object = Object(new, parameters);重置对象 object = Object(new, parameters);
【发布时间】:2012-07-20 06:49:24
【问题描述】:

我有一个简单的课程:

class Histogram {
    int m_width;
    int m_height;
    int m_sampleSize;
    int m_bufferWidth;
    int m_bufferHeight;

    uint8* m_buffer;
    int m_size;
public:
    Histogram() : m_buffer(0) { }
    Histogram(int width, int height, int sampleSize) {
        m_buffer = new unsigned char [width*height*sampleSize];
    }
    ~Histogram() {
        my_log("destructor: buffer: %p", m_buffer);
        if ( m_buffer ) { delete [] m_buffer; m_buffer = NULL; }
    }
    unsigned char* buffer() {
        return m_buffer;
    }
};

它是其他类的成员:

class Other {
    Histogram m_histogram;

    void reset() {
        my_log("reset() called: buffer: %p", m_histogram.buffer());
        m_histogram = Histogram(512, 512, 2);
    }
}

现在,我首先使用 Histogram() 构造函数创建“未初始化”对象——它将 m_buffer 设置为 NULL;

然后,我调用 reset 方法,它执行 m_histogram = Histogram( 512, 512, 3 ) - 新对象已通过 new 初始化 m_buffer。

所以预期的日志消息顺序是:

  • "reset() 调用:缓冲区:0x0"
  • “析构函数:缓冲区:0x0”

但相反,我得到:

  • "reset() 调用:缓冲区:0x0"
  • “析构函数:缓冲区:0x072a7de”

因此正在执行一些不合理的操作。此外,当我还删除第二个对象(使用“更大”构造函数创建,具有三个 int 参数)时,会显示 0x072a7de 地址。

【问题讨论】:

  • 编译器生成的默认复制构造函数和赋值运算符不能很好地处理指针。您需要遵守 rule of three(或 C++11 中的五个)参见:stackoverflow.com/a/255744/14065

标签: c++ constructor copy-constructor


【解决方案1】:

你必须为你的类 Histogram 实现 copy-ctor 和赋值运算符,因为

m_histogram = Histogram(512, 512, 2);

是赋值运算符调用。隐式运算符 = 类的按位复制成员。

而且你必须在析构函数中使用delete[],而不是delete,因为你分配了一个数组。

【讨论】:

    【解决方案2】:

    首先,由于你指向的是一个动态分配的数组,所以需要使用运算符delete[]

    delete[] m_buffer;
    

    其次,更重要的是,由于您已经动态分配了内存,您应该遵循rule of three 并实现复制构造函数和赋值运算符,以及修复析构函数。

    现在发生的事情是您的(编译器合成的)赋值运算符正在制作“浅”副本,即它正在复制指针。然后你会有多个析构函数试图删除它。您正在调用未定义的行为。

    使用std::vector<uint8> 作为缓冲区确实可以为自己省去很多麻烦。

    【讨论】:

    • 对不起,在原始代码中我确实使用了 delete[]。至于其余的,我认为会发生以下顺序:a)删除旧的 m_histogram,b)构造新的直方图(512,...),c)将其复制到 m_histogram 使用的空间。它也可以直接在旧空间中创建新的直方图。您的回答表明,a) 作为最后一步完成?
    • @GameTCoder 表达式的 RHS 创建新的直方图,但赋值运算符用于分配给 LHS。这只是制作 RHS 指针的浅拷贝。 RHS 是临时的,会被删除,所以你在 LHS 中留下了一个悬空指针。
    • 谢谢!这解释了意外行为。
    猜你喜欢
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 2014-02-10
    • 2013-01-16
    • 1970-01-01
    • 2012-03-10
    • 2011-07-13
    • 1970-01-01
    相关资源
    最近更新 更多