C++ 中的类析构函数

问题描述 投票:0回答:1

我创建了一个类书,其中包含一些类属性,例如名称和作者(没有动态分配),然后我创建了一个类库,其中包含动态书籍数组(如 book* 集)及其大小和一些方法,因此在库类 I在析构函数中添加了一个“删除”运算符来释放“集合”的内存,因为集合是一个指针,但在书籍类中我只添加了一些文本,例如“析构函数被调用”以了解程序执行后我的所有书籍是否都会被删除或不。

主要问题是,首先我创建了 3 本书对象,然后创建了一个库对象,我在其中添加了所有 3 本书。 当我运行我的代码时,我看到库对象析构函数的消息,除了 3 之外,只有一本书析构函数,为什么会发生这种情况? 是否调用非动态对象的析构函数真的很重要吗? 因为我知道如果不调用动态对象的析构函数,那是一个真正的问题,因为它会导致内存泄漏,但我的情况又如何呢?有人可以解释一下它对于本地对象和一般动态实际上是如何工作的吗? (我刚刚学完OOP,所以我在理解这些东西时遇到了一些问题,也为我糟糕的英语感到抱歉)

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 << "Destuctor 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;
}
c++ oop pointers destructor
1个回答
0
投票
您的
library
课程是伪装的
std::vector

如果将成员函数

append
的名称改为
push_back
,你真的可以看到相似之处。

当我运行代码时,我看到库对象析构函数的消息,并且除了 3 个之外,只有一个书析构函数,为什么会发生这种情况?

这里的问题在评论中被多次指出。您忘记使用

delete
运算符的数组版本。这是您问题中的代码:

    ~library()
    {
        cout << "Destuctor of library was called.\n";
        delete set;
    }

这是更正:

    ~library()
    {
        cout << "Destuctor of library was called.\n";
        delete[] set;
    }

通过这个简单的改变,一切就位了。

这是输出:

Destuctor 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!

起初,调用

book ""
的 dtor 可能看起来很奇怪。然而,这是因为
book
的默认构造函数是由运算符
new
调用的。
library
的默认构造函数调用了两次,当您从函数
new
调用运算符
append
时,它被调用了四次。

追加三本书后,图书馆的最后一个位置仍然未使用。这就是您在输出中看到的被破坏的那个。

数组

set
的元素按照其构造的相反顺序被销毁。这解释了上面输出中显示的析构函数调用的顺序。前四个显示
myLib
被摧毁。最后三个显示函数
main
中的局部变量被销毁。

是否调用非动态对象的析构函数真的很重要吗?

这个问题没有实际意义。每当对象的生命周期结束时,就会调用对象的 dtor。即使一个对象是在堆栈上分配的,调用析构函数也很重要。您的

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;
}

© www.soinside.com 2019 - 2024. All rights reserved.