C ++ Singleton构造函数和析构函数

时间:2010-05-04 00:07:44

标签: c++ constructor singleton destructor

如果头文件或源文件中提供了构造函数/析构函数实现,这是否重要?例如,哪种方式更受欢迎?为什么?

方式1:

class Singleton
{
  public:
    ~Singleton() { }

  private:
    Singleton() { }
};

方式2:

class Singleton
{
  public:
    ~Singleton();

  private:
    Singleton();
};

在源.cc文件中:

Singleton::Singleton()
{
}

Singleton::~Singleton()
{
}

最初,我在源文件中有实现,但我被要求删除它。有谁知道为什么?

5 个答案:

答案 0 :(得分:2)

没关系,但通常最好(在我最卑鄙的意见中)在.cpp文件中定义它们,以便隐藏类的用户的实现。

答案 1 :(得分:1)

如果在头文件中定义了一个函数(即函数的主体在头文件中),则编译器可以选择将inline函数作为优化。如果在源文件中定义了该函数,则编译器无法对其进行内联。除此之外,确实没有任何区别。

然而,有些人会争辩说你应该尽可能地将函数定义放在源文件中,以便使用头文件的人不会看到函数定义。

一般来说,如果你有一个很短的函数,你认为很有可能被内联,那么把它放在头文件中是个好主意,这样编译器就可以进行优化。否则,最好将它放在源文件中,它不会使事情变得混乱。理想情况下,头文件无论如何都会显示API,而不是实现。

对于单例的构造函数和析构函数,它们只会在整个程序中被调用一次,所以你没有通过内联它们获得任何东西,所以如果你正在做的话你也可以将它们粘在源文件中其中很多东西。但如果它们是空的,为什么要浪费源文件中的空间呢?只需将它们放在头文件中即可。

答案 2 :(得分:0)

以一些微妙的方式重要。头文件中定义的函数(你的“方式1”)可能(根据我的经验,通常是)内联声明(但是,与内联一样,如果函数很大,它可能实际上不是由编译器内联)。这可能会导致问题,尤其是在处理抽象类时。

原因是vtable将包含在编译单元(.o文件)中,其中找到第一个非内联函数。如果内联所有函数,则无法找到v表,并且您的代码将无法链接。 (有很多方法可以解决这个问题,但那是另一个话题。)

因此,对于更有组织的代码,使用方式2,特别是对于具有大量成员函数和/或长成员函数的类,以及在具有继承和虚函数的情况下。使用方法1用于非常短的类(整个头文件将小于约100-200行)。

答案 3 :(得分:0)

选择主要是风格,因为功能内联可能会或可能不会发挥作用。是的,头文件中的所有内容都可以内联,但很可能,您对函数内联的任何了解都是错误的。我知道我所知道的关于inilning的一切都是错误的,因为你无法选择编译器会做什么。所以在这种情况下我不会担心这个方面。

然而,我们可以在这里探讨另一个微妙之处。假设Singleton类中的构造函数是public:

class Singleton
{
public:
    Singleton(void);
    virtual ~Singleton(void);
};
//cpp file
Singleton::Singleton()
{
}


Singleton::~Singleton()
{
}

如果您将上述代码放入静态库中,那么您所拥有的本质上是一个无法在库外实例化的类。除了链接器之外,编译器不会阻止您这样做。这是您将得到的错误:

  

1> testrun.obj:错误LNK2001:未解析的外部符号“public:virtual __thiscall Singleton :: ~Singleton(void)”(?? 1Singleton @@ UAE @ XZ)
  1> testrun.obj:错误LNK2001:未解析的外部符号“public:__thiscall Singleton :: Singleton(void)”(?? 0Singleton @@ QAE @ XZ)
  1> C:\ temp \ sotest \ Debug \ testrun.exe:致命错误LNK1120:2个未解析的外部

答案 4 :(得分:-1)

一个区别是直接在类中添加实现会导致函数内联。