C++ 析构函数调用以前从未构造过的对象

C++ 析构函数调用以前从未构造过的对象,c++,object-destruction,C++,Object Destruction,我有以下代码 class Wave { int m_length; data_type * m_data; public: Wave(){ blah...blah...blah m_data = NULL; m_length = 0; cout << "Wave " << this << " created on " << m_data << " with m

我有以下代码

class Wave {

int m_length;
data_type * m_data;

public:

    Wave(){
        blah...blah...blah
        m_data = NULL;
        m_length = 0;
        cout << "Wave " << this << " created on " << m_data << " with m_length " <<  m_length << endl;
    }

    Wave(int len, data_type data){
        blah...blah...blah
        if (len) {
            m_length = len;
            m_data = new data_type [m_length];
        } else {
            m_length = 0;
            m_data = NULL;
        }
        cout << "Wave " << this << " created on " << m_data << " with m_length " <<  m_length << endl;
    }



    ~Wave() 
    {
    cout << "Wave " << this << " destructor  on " << m_data << " started ";
        if (m_length) delete[] m_data;
    cout << "and finished " << endl;
    };        





    Wave & operator+= (const Wave wave){
    cout << __FUNCTION__ << ":" << __LINE__ << " m_length " << m_length << endl;
    if (NULL != m_data){
        data_type * tBuf = new data_type [m_length + wave.Length()];
        copy (wave.begin(),wave.end(), copy (begin(),end(),iterator(tBuf)));
        cout << "Wave " << this << " data on " << m_data << " moved onto " << tBuf;
        delete[] m_data;
        m_data = tBuf;
        cout << " and deleted" << endl;
    } else {
        m_data = new data_type [wave.Length()];
        copy (wave.begin(), wave.end(), begin());
        cout << "Wave " << this << " data created on " << m_data << " of length " <<  wave.Length() << endl;
    }
    m_length += wave.Length();
    cout << __FUNCTION__ << ":" << __LINE__ << " m_length " << m_length << endl;
    return *this;
    };

}


main(){

blah..blah..blah

Wave sample;

for (......) {

    cout << pulseNum << "-th High part: " << pulse->first << endl;
    Wave tSample(x,y);
    blah.blah.blah

    sample += tSample;

    cout << endl << pulseNum++ << "-th Low part: " << pulse->second << endl;
    tSample = Wave(a,b);
    blah.blah.blah

    sample += tSample;
}

}
对我来说最奇怪的是,析构函数比构造函数被调用的次数更多。此外,它是为以前从未构造过但数据地址相同的对象调用的。

怎么可能呢

Wave
有一个编译器生成的复制构造函数,您看不到它的输出


例如,调用此复制构造函数是为了构造对象,该对象是
Wave&operator+=(const-Wave-Wave)
Wave
的参数,它有一个编译器生成的复制构造函数,您看不到任何输出


例如,调用此复制构造函数来构造对象,该对象是
Wave&operator+=(const-Wave-Wave)

的参数。如果要简化代码,只需定义
std::vector m_data
数据成员,而不是使用原始指针(
data_type*m_data

这样,编译器将自动为类生成适当的复制构造函数、复制运算符=(以及符合C++11的编译器的移动语义)和析构函数(自动生成的复制构造函数、复制运算符=和析构函数将按成员操作,例如,自动生成的复制构造函数将为类的每个数据成员调用复制构造函数)

要分配数据,请执行以下操作:

m_data = new data_type [m_length];
使用:

您还可以去掉
m_length
数据成员,因为
std::vector
知道它自己的大小(您可以通过
std::vector::size()
方法访问它)


请注意,
std::vector
将其所有元素存储在单个连续内存区域中(如
new[]
);您可以使用
&m_data[0]
访问该区域的开头。如果您想简化代码,只需定义一个
std::vector m_data
数据成员,而不是使用原始指针(
数据类型*m\u数据

这样,编译器将自动为类生成适当的复制构造函数、复制运算符=(以及符合C++11的编译器的移动语义)和析构函数(自动生成的复制构造函数、复制运算符=和析构函数将按成员操作,例如,自动生成的复制构造函数将为类的每个数据成员调用复制构造函数)

要分配数据,请执行以下操作:

m_data = new data_type [m_length];
使用:

您还可以去掉
m_length
数据成员,因为
std::vector
知道它自己的大小(您可以通过
std::vector::size()
方法访问它)



请注意,
std::vector
将其所有元素存储在单个连续内存区域中(如
new[]
);您可以使用
和m_数据[0]访问该区域的开头< /代码> .

管理自己的堆内存是非常糟糕的。使用<代码> STD::向量< /代码>。管理自己的堆内存非常糟糕。使用<代码> STD::向量< /代码>。OP:你可以考虑声明<代码>波和算符+=(const wave and wave)。
这将节省大量的复制操作。Steeve@那么,当两次调用析构函数删除同一个数据缓冲区时会发生什么情况?例如:0xc61250上的Wave 0x28fee0析构函数启动和完成0xc61250上的Wave 0x28fe54析构函数启动和完成finished@OlegG:双重释放缓冲区时,行为未定义(这是另一种说法,代码中有一个bug)。因为原始对象和副本都有一个指向同一个缓冲区的指针,所以它们都会在其析构函数中释放它。@ toHexz酷。非常感谢:OP:你可以考虑声明<代码>波和算符+=(const wave and wave)。这将节省大量的复制操作。Steeve@那么,当两次调用析构函数删除同一个数据缓冲区时会发生什么情况?例如:0xc61250上的Wave 0x28fee0析构函数启动和完成0xc61250上的Wave 0x28fe54析构函数启动和完成finished@OlegG:双重释放缓冲区时,行为未定义(这是另一种说法,你的代码中有一个bug)。由于原始对象和副本都有指向同一缓冲区的指针,它们都会在析构函数中释放它。@tohecz很酷。非常感谢:)C64先生@要求所有数据类型为
的托管对象必须位于连续内存区域中,然后将其传递给另一个过程。vector允许我这样做吗?@OlegG:是的,
vector
将其所有元素存储在一个连续内存区域中。@Steve我如何将该区域的地址传递给一个过程需要
void*
类型的参数吗?@OlegG:是的,请参阅Steve Jessop的评论。@OlegG:我编辑了这篇文章,添加了一句话来解决您关于内存连续性的问题,并解决了该内存区域的开头。C64先生@要求所有
数据类型的托管对象必须位于连续的内存中ory区域将被传递给另一个过程。vector允许我这样做吗?@OlegG:是的,
vector
将其所有元素存储在一个连续的内存区域中。@Steve,我如何将该区域的地址传递给一个需要
void*
类型参数的过程?@OlegG:是的,请参阅Steve Jessop的评论。@OlegG:我编辑这篇文章增加了一句话来回答你关于记忆连续性的问题,并指出了记忆区域的开始。
m_data.resize(m_length);