c++中,单例类的析构函数被再次调用
C++, destructor of a singleton class is called once again
我创建了一个简单的单例类。在运行测试时,我得到了一些奇怪的结果。
再次调用析构函数。
这是结果和我的代码
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,只需:
- 添加
- 将默认构造函数设为private(并且只在
instance
方法中调用) - 删除复制构造函数
instance
静态功能这将防止创建多个类型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;
}
要使其工作,您应该:
- 将
Singleton
的构造函数、复制构造函数和赋值操作符设置为protected(非private)。 -
从Singleton模板中派生TestClass
类TestClass:公共单例{…};
试着让我知道它是否适合你;)
- 什么时候调用析构函数
- C++-明确何时以及如何调用析构函数
- C++ 防止在映射中放置()时调用析构函数
- 调用析构函数以释放动态分配的内存
- C++:使用方法调用析构函数的顺序是什么?
- 向量推回调用析构函数时调用析构函数
- 如何在调用析构函数时优雅地停止/销毁带有阻塞调用C++线程?
- C++,我应该调用析构函数吗?
- 如何获取有关在 Clang LibTooling 中调用析构函数的信息?
- 当我从 std::vector 中的新放置调用析构函数时会发生什么?
- 为什么这里不调用析构函数
- 在调用 std::bind 的产品后意外调用析构函数
- 为什么在传递给函数而不是构造函数时调用析构函数?
- 如何在C++中调用析构函数
- 为什么为未删除的对象调用析构函数?
- 调用析构函数时出错
- C++ 在不释放内存的情况下调用析构函数
- 为什么在运算符删除中不调用析构函数?
- C++ 调用析构函数后动态模板队列"double free or corruption (out)"
- 在 postOrderDelete 上调用析构函数时引发的异常