在 C++ 显式调用析构函数

Jinku Hu 2021年4月29日
在 C++ 显式调用析构函数

本文将介绍几种如何在 C++ 中显式调用析构函数的方法。

使用 obj.~ClassName() 表示法明确调用析构函数

析构函数是特殊函数,当对象自动超出范围或由用户显式调用删除时,析构函数将执行。注意,这些函数通常用于释放给定对象使用的资源。即使可以将析构函数显式调用为成员函数,也无需这样做。在大多数情况下,动态分配类数据成员会导致资源的双重释放。后一种情况通常会导致程序异常终止。

在下面的示例中,我们演示定义的类-MyClass,该类具有两个构造函数和一个内置方法来检索唯一数据成员的值。还定义了析构函数,并使用构造函数将析构函数将相应的消息打印到 cout 流中,以使我们更容易调查行为。

请注意,以下示例代码显示了两个析构函数消息,其中一个由显式用户调用触发,而另一个则在程序退出时自动调用。虽然,如果在构造函数中为 MyClass 数据成员分配了 new 运算符,则此示例将导致程序异常终止-可能是双重错误。

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

class MyClass {
public:
    explicit MyClass(string s):
            str(std::move(s)) { cout << "Constructor 1 executed\n"; }

    MyClass(const MyClass &s):
            str(string(s.str)) { cout << "Constructor 2 executed\n"; }

    ~MyClass() { cout << "Destructor executed\n"; }

    string& getString() { return str; };
private:
    string str;
};

int main()
{
    MyClass str1("Hello There! ");

    cout << endl;
    cout << "str1: " << str1.getString() << endl;
    cout << endl;

    str1.~MyClass();

    return EXIT_SUCCESS;
}

输出:

Constructor 1 executed

str1: Hello There!

Destructor executed
Destructor executed

另外,我们可以看到以下版本的代码触发了相同数量的构造函数/析构函数,这实际上是该概念背后的思想。因此,即使最后一个示例可以正常工作,也不建议显式调用析构函数。

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

class MyClass {
public:
    explicit MyClass(string s):
            str(std::move(s)) { cout << "Constructor 1 executed\n"; }

    MyClass(const MyClass &s):
            str(string(s.str)) { cout << "Constructor 2 executed\n"; }

    ~MyClass() { cout << "Destructor executed\n"; }

    string& getString() { return str; };
private:
    string str;
};

int main()
{
    MyClass str1("Hello There! ");
    MyClass str2(str1);

    cout << endl;
    cout << "str2: " << str2.getString() << endl;
    cout << endl;

    return EXIT_SUCCESS;
}

输出:

Constructor 1 executed
Constructor 2 executed

str2: Hello There!

Destructor executed
Destructor executed

要考虑的另一种情况是,用 new 运算符分配了类对象,并且在程序退出之前,在同一对象上调用了 delete。请注意,在执行描述符函数后,将打印最后一个 cout 语句,这意味着在调用 delete 运算符时会调用该描述符。

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

class MyClass {
public:
    explicit MyClass(string s):
            str(std::move(s)) { cout << "Constructor 1 executed\n"; }

    MyClass(const MyClass &s):
            str(string(s.str)) { cout << "Constructor 2 executed\n"; }

    ~MyClass() { cout << "Destructor executed\n"; }

    string& getString() { return str; };
    string* getStringAddr() { return &str; };
private:
    string str;
};

int main()
{
    auto *str4 = new MyClass("Hello There! ");

    cout << endl;
    cout << "str4: " << str4->getString() << endl;
    cout << endl;

    delete str4;
    cout << "exiting" << endl;

    return EXIT_SUCCESS;
}

输出:

Constructor 1 executed

str4: Hello There!

Destructor executed
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn

相关文章 - C++ Class