2013-06-20 55 views
1

我做了一个简单的单例类。 运行测试时,我得到了一些weired结果。C++,单例类的析构函数再次被调用

析构函数被再次调用。

这是结果和我的代码。

结果:我预计析构函数被调用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_ 

的main.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; 
} 
+2

这不是一个真正的单身人士,对不对?你的构造函数和析构函数应该是私有的;由GetInstance中的静态声明创建的实例应该是唯一的(如果您遵循正确的模式)。 –

回答

8

实际上,你有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++ Singleton design pattern有益的讨论。

如果C++ 11是可用的,最好是用

private: 
    Singleton() = default; 
    ~Singleton() = default; 

    Singleton(const Singleton&) = delete; 
    Singleton& operator=(const Singleton&) = delete; 

这确保了没有人,甚至不是类本身,可以调用拷贝或复制分配功能。

+4

如果C++ 11可用,最好替换这些'; //不要用'= ​​delete;'实现''。这确保了没有人,甚至不是类本身,都可以调用复制或复制分配功能。你可以使用'= default;'而不是空的大括号用于私有构造函数和析构函数。 – bames53

+0

@ bames53感谢您的建议。 – Yang

0

模板中的“静态类型实例”正在创建另一个实例。

0

您错误地使用了迈尔的单身模式。

的getInstance应该有形式:

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

它会比这个修复更好一点。创建'TestClass'的副本没有限制。 –

1

因此,有一个Singleton模板类是矫枉过正,而不是必要的。 Singleton是一种设计模式,而不是一种类型。

对于你想一个单身,只是每个类T:

  1. 添加instance静态函数
  2. 使私有的默认构造函数(只有调用它instance法)
  3. 删除复制构造函数

这将阻止创建多个类型为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。

0

得到它的工作,你应该:

  1. 制作Singleton的构造函数,拷贝构造函数和受保护的赋值运算符(不是私人)。
  2. 从Singleton模板派生TestClass。

    class TestClass:public Singleton { ... };

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