在C++到第一个对象中创建第二个对象时,第一个对象会去哪里?

When creating a second object in C++ through the first object, where does the first object go?

本文关键字:一个对象 第二个 C++ 创建 对象      更新时间:2023-10-16

我目前正在阅读赫伯特·希尔特(Herbert Schildt(的《C++:初学者指南》第二版。

在模块 9.4 中,他谈到了返回对象:

正如对象可以传递给函数一样,函数也可以返回对象。要返回对象,请先声明 作为返回类类型的函数。其次,使用正常返回返回该类型的对象 陈述。以下程序有一个名为 mkBigger( ( 的成员函数。它返回一个对象 为 val 提供一个比调用对象大两倍的值。

这是他提到的"以下程序":

// Returning objects.
#include <iostream>
using namespace std;
class MyClass {
int val;
public:
// Normal Constructor.
MyClass(int i) {
val = i;
cout << "Inside constructorn";
}
~MyClass() {
cout << "Destructingn";
}
int getval() { return val; }
// Return an object.
MyClass mkBigger() {
Myclass o(val * 2); // mkBigger() returns a MyClass object.
return o;
}
};
void display(MyClass ob)
{
cout << ob.getval() << 'n';
}
int main()
{
cout << " Before Constructing a.n";
MyClass a;
cout << "After constructing a.nn";
cout << "Before call to display.n";
display(a);
cout << "After display() returns.nn";
cout << "Before call to mkBigger().n";
a = a.mkBigger();
cout << "After mkBigger() returns.nn";
cout << "Before second call to display.n";
display(a);
cout << "After display() returns.nn";
return 0;
}

这给了我们以下输出:

Before Constructing a.
Inside constructor
After constructing a.
Before call to display.
10
Destructing
After display() returns.
Before call to mkBigger()
Inside constructor
Destructing
Destructing
After mkBigger() returns.
Before second call to display.
20
Destructing
After display() returns.
Destructing

Schildt 接着解释说,在 mkBigger(( 调用期间有两个"破坏"消息的原因是:

当函数返回对象时,会自动创建一个临时对象,该对象保存返回值。函数实际返回的正是此对象。返回值后,将销毁此对象。

我真的很惊讶没有3条"破坏"消息。我有以下问题:给定 mkBigger(( 的定义,创建了一个新的 MyClass 实例,并且该实例被返回并放置在a的地址中。因此,当做

a = a.mkBigger();

因此,我的印象是,以前保存在 a 中的原始对象不再被a引用。这是对的吗?如果是这样,那么我有以下问题:

有人告诉我C++有一些垃圾收集的微小概念。因此,该物品会被垃圾收集吗?这个对象现在在哪里?这是许多人在谈论C++的"危险"时提到的可能令人恐惧的记忆泄漏的一个例子吗?

mkbigger()中的一个析构函数在o上调用,MyClass 实例按值传入;它在函数结束时超出范围。另一个是在销毁时返回的o的临时副本上调用的。还有什么超出范围?main()a;因此,不应期望调用第三个析构函数。当自动对象超出范围时,C++ 不会在调用析构函数之外提供垃圾回收。

与其他一些现代语言不同,a不会"保留对对象的引用";a对象,因为它是保存原始数据成员的一定数量的字节。当你执行a = a.mkBigger();时,调用MyClass的默认赋值运算符,它只是将右侧临时对象内的val复制到a内部的val中,覆盖已经存在的值。a = a.makeBigger()相当于a.val = a.makeBigger().val如果val是公开的。

当您使用new分配内存,然后无法使用delete来释放该内存时,会发生内存泄漏。对于在内部执行此操作的类,必须至少编写自己的复制构造函数、赋值运算符和析构函数。

相关文章: