提问人:comediann 提问时间:8/27/2023 最后编辑:Peter Mortensencomediann 更新时间:9/4/2023 访问量:129
C++ 中的类析构函数
Class destructor in C++
问:
我创建了一个具有一些类属性的类书,例如名称和作者(没有动态分配),然后我创建了一个包含动态书数组(如 book* set)及其大小和一些方法的类库,因此在库类中,我向析构函数添加了一个“delete”运算符来释放“set”的内存,因为 set 是一个指针, 但是在书课上,我只添加了一些文本,例如“析构函数被调用”,以了解程序执行后我所有的书是否会被删除。
主要问题是,首先我创建了三个 book 对象,然后我创建了一个 library 对象,在那里我添加了所有 3 本书。当我运行我的代码时,我看到库对象析构函数的消息,除了 3 之外只有一个书籍析构函数,为什么会发生这种情况?是否调用非动态对象的析构函数真的重要吗?
因为我知道,如果不调用动态对象的析构函数,这是一个真正的问题,因为它会导致内存泄漏,但是我的情况呢?
它如何实际适用于局部对象和一般动态对象?
class book
{
private:
string title;
string author;
public:
book() { title = ""; author = ""; }
book(string n, string a) : title(n), author(a) {}
string getTitle() { return title; }
string getAuthor() { return author; }
book& operator=(const book& other)
{
title = other.title;
author = other.author;
return *this;
}
~book() { cout << "Destructor of book \"" << title << "\" " << "was called!\n"; }
};
class library
{
private:
book* set;
int size;
int ptr;
public:
library()
{
size = 2;
ptr = 0;
set = new book[size];
}
void append(book &a)
{
if(ptr < size)
{
set[ptr] = a;
ptr++;
}
else // Here I am just treating it as a simple dynamic
// array, so if I run out of space, I create a
// new dynamic array with n*2 size
{
book* copy = new book[size*2];
for(int i = 0; i < size; i++)
copy[i] = set[i];
set = copy;
set[ptr++] = a;
size *= 2;
}
}
~library()
{
cout << "destructor of library was called.\n";
delete set;
}
};
int main()
{
book one("Harry Potter", "J. K. Rowling");
book two("The Little Prince", "Antoine de Saint-Exupery");
book three("The Secret garden", "Frances Hodgson Bumett");
library myLib;
myLib.append(one);
myLib.append(two);
myLib.append(three);
return 0;
}
答:
你的班级是伪装的。library
std::vector
如果将成员函数的名称更改为 ,则可以真正看到相似性。append
push_back
第1项质询
当我运行我的代码时,我看到库对象析构函数的消息,除了 3 之外只有一个书籍析构函数,为什么会发生这种情况?
这里的问题在评论中被多次发现。您忘记使用运算符的数组版本。以下是您在问题中的代码:delete
~library()
{
cout << "Destructor of library was called.\n";
delete set;
}
这是更正:
~library()
{
cout << "Destructor of library was called.\n";
delete[] set;
}
通过这个简单的更改,一切都会立即到位。
输出如下:
Destructor of library was called.
Destructor of book "" was called!
Destructor of book "The Secret garden" was called!
Destructor of book "The Little Prince" was called!
Destructor of book "Harry Potter" was called!
Destructor of book "The Secret garden" was called!
Destructor of book "The Little Prince" was called!
Destructor of book "Harry Potter" was called!
起初,调用析构函数似乎很奇怪。然而,这可以通过以下事实来解释:默认构造函数 是由 operator 调用的。默认构造函数为 调用了两次,当您从函数 调用运算符时,它被调用了四次。book ""
book
new
library
new
append
在附加了三本书后,图书馆的最后一个插槽仍未使用。这就是您在输出中看到的被破坏的那个。
数组的元素以其构造的相反顺序被销毁。这解释了上面输出中显示的析构函数调用的顺序。前四个节目被摧毁了。最后三个显示了函数中被销毁的局部变量。set
myLib
main
哦不!内存泄漏...
在函数中,您忘记删除旧数组。这是修复:append
void append(book& a)
{
if (ptr < size)
{
set[ptr] = a;
ptr++;
}
else // Here I am just treating it as a simple dynamic array, so if I run out of space, I create a new dynamic array with n*2 size
{
book* copy = new book[size * 2];
for (int i = 0; i < size; i++)
copy[i] = set[i];
std::swap(set, copy); // Swap the pointers
delete[] copy; // Then, delete the copy.
set[ptr++] = a;
size *= 2;
}
}
这为您提供了对析构函数的另外两个调用:book
Destructor of book "The Little Prince" was called!
Destructor of book "Harry Potter" was called!
Destructor of library was called.
Destructor of book "" was called!
Destructor of book "The Secret garden" was called!
Destructor of book "The Little Prince" was called!
Destructor of book "Harry Potter" was called!
Destructor of book "The Secret garden" was called!
Destructor of book "The Little Prince" was called!
Destructor of book "Harry Potter" was called!
第2项质询
是否调用非动态对象的析构函数真的重要吗?
这个问题没有实际意义。每当对象的生存期结束时,都会调用对象的析构函数。即使在堆栈上分配了对象,调用析构函数也很重要。你的班级就是一个例子。虽然它不包含您创建的任何动态分配的数据,但它确实包含一对对象,并且这些对象可能确实将数据存储在堆上。book
std::string
生产代码呢?
您的库程序可能是了解动态分配数据的好练习。每个人迟早都需要做这样的事情。但是,在生产代码中,最好使用标准库中的容器之一。
class library
{
private:
std::vector<book> books;
public:
library() {
books.reserve(2);
}
void append(book& a) {
books.push_back(a);
}
// ...
};
您甚至可以完全消除类:library
int main()
{
book one("Harry Potter", "J. K. Rowling");
book two("The Little Prince", "Antoine de Saint-Exupery");
book three("The Secret garden", "Frances Hodgson Bumett");
std::vector<book> myLib;
myLib.push_back(one);
myLib.push_back(two);
myLib.push_back(three);
return 0;
}
评论
[]
与delete
混淆set<Book*>
set<Book>
set<unique_ptr<Book>>
new
delete
vector
unique_ptr
delete
delete []