【问题标题】:why private destructor getting called when obj is created statically为什么在静态创建对象时调用私有析构函数
【发布时间】:2013-10-29 20:01:07
【问题描述】:

我已经问过一个与私有析构函数相关的问题 (Use of making destructor private),但我已经以下面这个问题结束了,但我仍然不明白确切的答案。

问题:

为什么当我创建一个具有私有析构函数的类对象时会调用私有析构函数?但不是当我创建一个普通对象时。

案例一

// myclass.h

#include <iostream>

class MyClass {
public:
    static MyClass& GetInstance();
    void Display();
private:
    MyClass();
    virtual ~MyClass();
};

MyClass::MyClass() {
    std::cout << "Constructor " << std::endl;
}

MyClass::~MyClass() {
    std::cout << "Destructor" << std::endl;
}

MyClass& MyClass::GetInstance() {
    static MyClass _instance;
    return _instance;
}

void MyClass::Display() {
    std::cout << "Hello" << std::endl;
}
// main.cpp

#include "myclass.h"
#include <iostream>

int main() {

    MyClass::GetInstance().Display(); //case1



    std::cout << "main finished!" << std::endl;

    return 0;
}

// output
Constructor 
main finished
Destructor.

案例二

// myclass.h

#include <iostream>

class MyClass {
public:
    void Display();
    MyClass();
    virtual ~MyClass();
};

MyClass::MyClass() {
    std::cout << "Constructor " << std::endl;
}

MyClass::~MyClass() {
    std::cout << "Destructor" << std::endl;
}

MyClass& MyClass::GetInstance() {
    static MyClass _instance;
    return _instance;
}

void MyClass::Display() {
    std::cout << "Hello" << std::endl;
}
// main.cpp

#include "myclass.h"
#include <iostream>

int main() {

    MyClass testObj;



    std::cout << "main finished!" << std::endl;

    return 0;
}

// Error
1>e:\programs\cpp_test\src\main.cpp(38): error C2248: 'MyClass::MyClass' : cannot access private member declared in class 'MyClass'
1>          e:\programs\cpp_test\static_single_test.h(11) : see declaration of 'MyClass::MyClass'
1>          e:\programs\cpp_test\static_single_test.h(6) : see declaration of 'MyClass'
1>e:\programs\cpp_test\src\main.cpp(38): error C2248: 'MyClass::~MyClass' : cannot access private member declared in class 'MyClass'
1>          e:\programs\cpp_test\static_single_test.h(12) : see declaration of 'MyClass::~MyClass

编辑

我知道当我们“仅需要基于堆的对象”时,需要将析构函数设为保护/私有。

http://en.wikibooks.org/w/index.php?title=More_C%2B%2B_Idioms%2FRequiring_or_Prohibiting_Heap-based_Objects&diff=2567824&oldid=2202430&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+MoreCppIdiomsWikibook+%28Wikibooks+-+Changes+related+to+%22More+C%2B%2B+Idioms%22+[en]%29

【问题讨论】:

  • 您在 2. 案例中遇到的错误表明您正在使用 1. 案例中的头文件。如果你使用了你声称使用的头文件,你应该得到一个关于 GetInstance() 未声明而不是构造函数/析构函数的错误。因此,请仔细检查您的设置。

标签: c++ constructor


【解决方案1】:

静态函数是类的函数,因此它可以访问该类的private函数,这就是为什么1个案例可以正常工作的原因。

在第一种情况下 - 对象将在函数Instance 中创建,该函数可以访问此类的构造函数。由于对象被声明为static - 它只会在程序结束时被销毁,因为对象是在类函数中创建的 - 可以访问析构函数。

在第二种情况下 - 您试图在 main 函数中创建 MyClass 类型的对象,该函数不是类函数,因此它无法访问 c-tor/d-tor。

【讨论】:

  • 意思是私有、公有和受保护是编译器时间限制...对。如果我试图形成错误的概念,请纠正我。因为无论对象超出范围,编译器在编译时都必须在下面添加代码以调用析构函数?如果这是正确的,这意味着编译器必须在程序终止时调用了它的析构函数,并且静态变量超出了范围。
  • @dearvivekkumar 想想你的第一个案例,比如在函数中构造静态对象并在函数中破坏这个对象,因为可以访问 d-tor/c-tor。
  • 是的,我正在尽力而为。但是当我调用 GetInstance() 时,该函数结束了,它的堆栈将被弹出。所以析构函数必须在 MyClass 的任何函数之外调用。但我感谢您到目前为止的时间和解释。 :)
  • @dearvivekkumar 是真的。真的,可能在全局范围内有两个函数(构造函数/析构函数)。由于静态变量的创建/销毁是在运行时执行的——它们实际上可以构造/销毁,因为运行时没有访问规则。
【解决方案2】:

在这两种情况下,都需要析构函数在对象的静态或自动生命周期结束时销毁对象,因此必须在声明对象的地方可访问。

在第一种情况下,对象是在类的成员中声明的,因此析构函数是可访问的并且编译成功。

第二种情况,对象是在非成员函数中声明的,所以析构函数不可访问,编译失败。

【讨论】:

    【解决方案3】:

    main 返回或调用std::exit 后,具有静态存储持续时间的对象将被销毁。标准的第 3.6.3 节描述了这种破坏。从 C++11、3.6.3、

    具有静态存储持续时间的已初始化对象(即生命周期已开始的对象)的析构函数作为从 main 返回的结果和调用 std::exit 的结果而被调用。

    请注意,没有提及析构函数的可访问性(公共/受保护/私有)。适当的析构函数被称为句号。

    第 12.4 节介绍了可访问性。 C++11 12.4 第 11 段(C++03 中的第 10 段)指出

    如果声明了一个类类型的对象或其数组,并且该类的析构函数在声明时不可访问,则该程序是非良构的。

    析构函数可以在静态函数MyClass::GetInstance() 中访问,因此在该函数中声明的块作用域静态变量是可以的。 main()中的析构函数不可访问,所以main中声明的自动变量不行。

    【讨论】:

      【解决方案4】:

      所有对象在超出范围时都会被销毁,而声明为静态的对象在程序结束时会超出范围,这正是您在第一个示例中看到的。将析构函数声明为私有仅意味着您可以在同一个类中创建(和销毁)实例。

      【讨论】:

        【解决方案5】:

        虽然我不明白您要达到什么目的,但错误很明显:

        在您的第一种情况下,构造对象的行位于类内部,因此可以访问所有私有方法。

        在您的第二种情况下,构造在类之外,因此无法访问私有成员。

        【讨论】:

          猜你喜欢
          • 2020-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-12
          • 2014-06-13
          • 1970-01-01
          • 2010-12-20
          • 1970-01-01
          相关资源
          最近更新 更多