c++中,单例类的析构函数被再次调用

C++, destructor of a singleton class is called once again

本文关键字:调用 析构函数 单例类 c++      更新时间:2023-10-16

我创建了一个简单的单例类。在运行测试时,我得到了一些奇怪的结果。

再次调用

析构函数。

这是结果和我的代码

Result:我期望析构函数被调用4次,因为我调用了GetInstance() 4次。但是 Desctuructor被调用5次!

Start Test
TestClass Constructor
   TestClass Destructor
   TestClass Destructor
   TestClass Destructor
   TestClass Destructor
   TestClass Destructor

singleton.h

#ifndef SINGLETON_H_
#define SINGLETON_H_
#include "basictype.h"
namespace common {
namespace internal {
// Usage :
// MyClass mine = common::internal::Singleton<MyClass>::GetInstace();
// mine.foo();
// This Singleton class is maybe the best one avoiding memory allocation.
// See http://stackoverflow.com/questions/1008019/c-singleton-design-pattern/1008289#1008289
template <typename Type>
class Singleton {
 public:
  static Type& GetInstance() {
    static Type instance;
    return instance;
  }
 private:
  Singleton() {};
  DISALLOW_COPY_AND_ASSIGN(Singleton);
};
}  // namespace internal
}  // namespace common
#endif  // SINGLETON_H_

c

#include <iostream>
#include "singleton.h"
class TestClass {
 public:
  TestClass() {
    std::cout << "TestClass Constructor" << std::endl;
  }
  ~TestClass() {
    std::cout << "   TestClass Destructor" << std::endl;
  }
};
void runSingletonTest() {
  TestClass tc = common::internal::Singleton<TestClass>::GetInstance();
  TestClass tc2 = common::internal::Singleton<TestClass>::GetInstance();
  TestClass tc3 = common::internal::Singleton<TestClass>::GetInstance();
  TestClass tc4 = common::internal::Singleton<TestClass>::GetInstance();
}
int main(){
  std::cout << "Start Test" << std::endl;
  runSingletonTest();
  return 0;
}

您的代码中实际上有5个TestClass实例。

第一个由

创建
static Type instance;

使用默认构造函数。这将在您的输出中产生TestClass Constructor行。

其他4个是由

创建的
TestClass tc = common::internal::Singleton<TestClass>::GetInstance();
TestClass tc2 = common::internal::Singleton<TestClass>::GetInstance();
TestClass tc3 = common::internal::Singleton<TestClass>::GetInstance();
TestClass tc4 = common::internal::Singleton<TestClass>::GetInstance();

使用复制构造函数。复制构造函数是由编译器生成的,它不输出任何东西(这就是为什么在输出中只看到一个TestClass Constructor)。因此,有5个TestClass实例被销毁。

注意:你的Singleton类不是真正的单例。要正确地遵循单例模式,应该禁止复制和赋值,方法是将(复制)构造函数和析构函数声明为private:

template <typename Type>
class Singleton {
public:
  static Type& GetInstance() {
    static Type instance;
    return instance;
  }
private:
  Singleton() {}
  ~Singleton() {}
  // Dont forget to declare these two. You want to make sure they
  // are unaccessable otherwise you may accidently get copies of
  // your singleton appearing.
  Singleton(const Singleton&);                // Don't Implement
  Singleton& operator=(const Singleton&);     // Don't implement
};

有一些关于c++单例设计模式的有益讨论。

如果c++ 11可用,最好使用

private:
  Singleton() = default;
  ~Singleton() = default;
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;

这确保了没有人,甚至是类本身,可以调用copy或copy赋值函数。

所以有一个单例模板类是多余的,没有必要。单例是一种设计模式,而不是一种类型。

对于每个你想创建一个单例的类T,只需:

    添加instance静态功能
  1. 将默认构造函数设为private(并且只在instance方法中调用)
  2. 删除复制构造函数

这将防止创建多个类型T的实例。

尝试以下操作:

class TestClass {
public:
  // 1
  static TestClass& instance() { static TestClass x; return x; }
private:
  // 2
  TestClass() {
    std::cout << "TestClass Constructor" << std::endl;
  }
  // 3
  TestClass(const TestClass&) = delete;
  ~TestClass() {
    std::cout << "   TestClass Destructor" << std::endl;
  }
};
void runSingletonTest() {
  TestClass& tc = TestClass::instance();
  TestClass& tc2 = TestClass::instance();
  TestClass& tc3 = TestClass::instance();
  TestClass& tc4 = TestClass::instance();
}

现在您有4个对同一对象的引用,并且您不能意外地创建第二个TestClass。

模板中的"static Type instance"正在创建另一个实例。

您错误地使用了Meyer的单例模式。

getInstance的形式应该是:

Singleton & GetInstance() {
   static Singleton instance;
   return instance;
}

要使其工作,您应该:

  1. Singleton的构造函数、复制构造函数和赋值操作符设置为protected(非private)。
  2. 从Singleton模板中派生TestClass

    类TestClass:公共单例{…};

试着让我知道它是否适合你;)