C++ 构造函数/析构函数调用 &对动态创建的数据调用"new"是否会删除旧数据?

C++ Constructor/Destructor invocation & Does calling "new" on dynamically created data delete the old data?

本文关键字:数据 调用 new 是否 删除 析构 构造函数 函数调用 创建 动态 C++      更新时间:2023-10-16

在c++中,在保存new 'd数据的指针上调用new是否会删除旧数据?

我想说它不会,而且会导致泄漏。在已经包含数据的指针上调用new,肯定只是将指针指向新数据,而我们将失去对旧数据的引用?

我问,因为我正在看这个页面,我注意到在构造函数中已经建议OP这样做:

MyString::MyString()
{
     // A new, empty string contains zero characters plus a terminating zero.
     nlength = 1;
     nstring = new char[1];
     nstring[0] = '';
}
MyString::MyString(const char *input)
{
     // A new, copy of a C-string contains exactly the same number of characters in
     // the C-string plus a terminating zero.
     nlength = strlen( input ) + 1;
     nstring = new char[ nlength ];
     strcpy(nstring, input);
}
MyString::MyString(const MyString& S)
{
     nlength = S.nlength;  // we know this is correct!
     nstring = new char[ nlength ];
     strcpy( nstring, S.nstring );
}
//nstring is deleted in the destructor
MyString::~MyString()
{
    delete[] nstring;
}
这对我来说似乎很奇怪。如果nstring已经被定义,那么它会泄漏吗?没有?

然而,这些都是构造函数,所以我猜这里的逻辑是每个实例只调用一次。这说得通。但是,如果我执行以下操作,会发生什么呢?

MyString myString("test");
myString = MyString("test2"); //is the destructor invoked here?

如果在重新赋值myString时调用析构函数,那么这一切对我来说都是有意义的。

总之,我想确认两件事:

  • 如果您将new数据分配给已经具有new数据的指针,那么这将泄漏,正确吗?
  • 重新分配对象时,是否调用了对象的析构函数?

你对指针的行为是正确的:当指针被重新分配时,内存将不会被释放。

代码的问题(我更改了变量的名称以避免混淆):

MyString x("test");
x = MyString("test2");

表示第二行不再调用x的构造函数或析构函数。在c++中,每个对象只调用构造函数和析构函数一次。这段代码调用赋值操作符

序列调用将是:

  1. "test"调用x的构造函数
  2. 使用"test2"调用未命名临时对象的构造函数。
  3. 用临时对象调用x的赋值操作符
  4. 调用临时对象的析构函数。
  5. 在当前作用域的末尾,调用x的析构函数。

赋值操作符应该或多或少这样定义:

const MyString &MyString::operator=(const MyString&o)
{
    nlength = S.nlength;  // we know this is correct!
    delete []nstring;
    nstring = new char[ nlength ];
    strcpy( nstring, S.nstring );
    return *this;
}

这段代码当然不是异常安全的。如果这个new失败了会发生什么?物体会碎的!

const MyString &MyString::operator=(MyString o)
{
    swap(*this, o);
    return *this;
}

这被称为copy-n-swap习惯用法,或者类似的东西。当运行上面的点3时,对这个operator=的调用顺序将是:

  1. 调用o的复制构造函数,传递临时的。
  2. 交换othis的值
  3. 调用o的析构函数,这将删除第一个分配("test1")。

不,任何通过调用newnew[]返回的指针必须被相应的调用deletedelete[]释放。

int* x = new int;
x = new int; // Memory leak!

c++中的new是一个返回在堆上分配的对象的操作符。它不关心你赋给它什么。唯一重要的是,通过new返回的对象最终被传递给delete操作符。

In C++, does calling new on a pointer that holds new'd data delete the old data?

。您必须delete分配的内存。

If the destructor is invoked upon reassigning myString then it all makes sense to me.

MyString myString("test");
myString = MyString("test2"); //is the destructor invoked here?

你贴的代码很有趣。除了建筑之外,还要完成一项作业。您的类的问题是它缺少用户定义的赋值操作符(至少没有显示),因此内存泄漏。

在任何其他成员函数之前调用构造函数。因此,nstring不可能已经指向一些已分配的内存。

正如你所说,x = new int;delete任何x之前指向的(如果有的话)。

线路:myString = MyString("test2");呼叫myString.operator=( MyString("test2") );。你说得好像你认为它摧毁了MyString,然后建造了一个新的,但这并没有发生。它只是一个函数,我们称之为复制赋值操作符,你应该实现这个函数。

表达式MyString("test2")中包含了一个构造和一个销毁,但这并不影响myString

new不释放预分配的内存。如果您在释放资源之前使用new,那么获得内存泄漏。在您的示例中,执行myString = MyString("test2")确实会导致内存泄漏,因为复制赋值操作符(或移动赋值操作符,具体取决于编译器版本)不会清除nstring已经占用的内存。这两个函数都是由编译器提供的,因为您没有自己创建它们,它们的工作(默认情况下)只是复制(或移动)成员,而不考虑内存管理。