是否可以实现仅限标头的非模板类?

时间:2014-10-23 18:20:08

标签: c++ static namespaces

据我所知,在不违反一个定义规则的情况下,在头文件中实现非模板和非内联的唯一方法是实现这是匿名命名空间。

但我不确定在这种类方法实现中静态变量会发生什么:

// MyHeader.h
// ... pragma once, defines, etc. ...

// (anonymous namespace removed due to suggestions below)
// namespace
// {
    class A // a simplified single-threaded kind of Singleton
    { 
        // ... some private not static data ...
    public:
        static A& instance() 
        {
            static A instance;   // is it guaranteed to be module-global?
            return instance;
        }

        void doNothing();
    }

    // inline added as suggested in answers below
    // actually, I disabled inline in compile settings,
    // checked that inlining was not happened using disassembler, 
    // but `inline` keyword is needed and it matters. Any suggestions, why?
    inline void A::doNothing()
    {
        // it's a very long method, so long that I don't want to 
        // implement it as inline within class body.

        // but not so long to consider refactoring it to smaller functions :)
    }        
//}

// File executable_part1.cpp
// ... includes, etc. ....
A::instance().doNothing();

// File executable_part2.cpp
// ... includes, etc. ....
A::instance().doNothing();

主要问题是:

  • 是否保证instance是模块全局的?
  • 此可移植代码或行为是否是编译器实现定义的?

我在Windows上的MSVS 2012上试验过这段代码。我已经在2个.cpp文件中为3个模块中的每一个包含了这个头文件:一个可执行文件和两个dll,由可执行文件加载。总共6次。

没有命名空间:constuctor被调用3次,每次操作一次,操作系统级别为'模块。 使用命名空间:constuctor被调用6次,每个cpp文件一次。

更新: 如下所述,C ++ 03标准的第7.1.2章解决了我的问题。内联问题在这里。

2 个答案:

答案 0 :(得分:2)

您不应使用未命名的命名空间,因为每个翻译单元都有自己的结构A.

只是做

class A
{ 
    // ... some private not static data ...
public:
    static A& instance() 
    {
        static A instance;
        return instance;
    }

    void doNothing();
};

inline void A::doNothing()
{
    // it's a very long method, so long that I don't want to 
    // implement it as inline within class body.

    // but not so long to consider refactoring it to smaller functions :)
}
  • 在exe / dll之间不共享单例是正常的。
  • 使用未命名的命名空间,每个TU都有单例,而没有它,单个语句将为整个exe(和整个Dll)共享。

对于你的配置:1个exe用2个cpp,2个dll用2个cpp: 你的实验是正确的:6有未命名的命名空间,3有没有它。

答案 1 :(得分:-1)

我真的不明白这个问题(也许我错过了什么)所以保持你需要的东西。

据我所知,静态方法和数据属于类本身而不属于类的实例。 因此静态数据只存在一次,如果从不同的对象访问它们,则它们是相同的。 静态方法类似于普通的外部函数,并且没有this指针可供它们使用。 属于类的名称空间,因此每个类都可以实现具有相同名称的静态函数,并且不会发生名称冲突,因为它们的名称不相等,因为完全限定的名称是:“classOfAppartenence :: nameOfFunction”和完全限定的名称每个人的名字都不同。 基本上,如果您没有为类实现任何对象,则该类仅作为命名空间。