C++ 重置对象m_对象=对象(新,参数);

C++ 重置对象m_对象=对象(新,参数);,c++,constructor,copy-constructor,C++,Constructor,Copy Constructor,我有一个简单的课程: 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,

我有一个简单的课程:

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

然后,我调用重置方法,它不执行m_直方图=直方图(512,512,3)–新对象通过new初始化了m_缓冲区

因此,日志消息的预期顺序是:

  • “重置()调用:缓冲区:0x0”
  • “析构函数:缓冲区:0x0”
但是,我得到的是:

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

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

首先,由于您指向的是动态分配的数组,因此需要使用运算符
delete[]

delete[] m_buffer;
第二,也是更重要的一点,因为您已经动态分配了内存,所以应该遵循并实现复制构造函数和赋值运算符,以及修复析构函数

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


通过使用
std::vector
作为缓冲区,您确实可以省去很多麻烦。

首先,由于您指向的是动态分配的数组,因此需要使用运算符
delete[]

delete[] m_buffer;
第二,也是更重要的一点,因为您已经动态分配了内存,所以应该遵循并实现复制构造函数和赋值运算符,以及修复析构函数

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


通过使用
std::vector
作为缓冲区,您确实可以省去很多麻烦。

您必须为类直方图实现复制ctor和赋值运算符,因为

m_histogram = Histogram(512, 512, 2);
是接线员呼叫。隐式运算符=按位复制类的成员


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

您必须为类直方图实现复制构造函数和赋值操作符,因为

m_histogram = Histogram(512, 512, 2);
是接线员呼叫。隐式运算符=按位复制类的成员


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

编译器生成的默认复制构造函数和赋值运算符与指针的行为不符。您需要遵守三个(或C++11中的五个)的
规则。请参阅:编译器生成的默认复制构造函数和赋值运算符与指针的行为不一致。您需要遵守三个规则(或C++11中的五个规则)。请参见:对不起,在oryginal代码中,我使用了delete[]。至于其余的,我认为会出现以下顺序:a)删除旧的m_直方图,b)构造新的直方图(512,…),c)将其复制到m_直方图使用的空间。它还可以直接在旧空间中创建新的直方图。您的答案表示a)已作为最后一步完成?@GameTCoder表达式的RHS创建新的直方图,但赋值运算符用于分配给LHS。这只是RHS指针的一个浅拷贝。RHS是一个临时文件,会被删除,因此您会在LHS中留下一个悬空的指针。谢谢!这解释了意外行为。对不起,在oryginal代码中,我确实使用了delete[]。至于其余的,我认为会出现以下顺序:a)删除旧的m_直方图,b)构造新的直方图(512,…),c)将其复制到m_直方图使用的空间。它还可以直接在旧空间中创建新的直方图。您的答案表示a)已作为最后一步完成?@GameTCoder表达式的RHS创建新的直方图,但赋值运算符用于分配给LHS。这只是RHS指针的一个浅拷贝。RHS是一个临时文件,会被删除,因此您会在LHS中留下一个悬空的指针。谢谢!这解释了意外的行为。