单例实现:命名空间方法通常比单例类更可取吗?

时间:2017-10-21 04:31:27

标签: c++ static namespaces

(这个问题假定全局+唯一对象是目标。我想澄清一点,这并不意味着它是在询问或提倡使用/不使用单例或全局变量的if / why / when。)

我想知道我是否缺少关于C ++的技术性,所以我的问题是:

C ++中单例模式的名称空间实现是否有效?如果是这样,是否有理由不经常将其建议为更好的方法?

根据Google的样式指南,我们看到命名空间非成员函数优于静态成员函数,但仅在不共享静态数据时:

  

“而不是仅创建类以对静态成员函数进行分组   它不共享静态数据,而是使用名称空间。“

为什么回避让非成员函数共享在未命名的命名空间中声明的静态数据?这有什么不对,这解释了为什么命名空间通常不被建议作为在C ++中编写单例类的更好的替代方法?

因为我找不到命名空间方法的建议,但是尽管C ++没有强制使用类,但很容易找到类方法:

C++ Singleton design pattern

Can any one provide me a sample of Singleton in c++?

Singleton instance declared as static variable of GetInstance method

http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

Singleton: How should it be used

在源文件中使用带有未命名命名空间的命名空间:

  • 您可以通过静态数据进行“陈述”
  • 您可以获得将内容放入未命名的命名空间的额外隐私
  • 您仍然可以通过使用静态指针和从函数调用构造来控制其静态对象的构造顺序。
  • 您不需要实现单例类

编辑 - 我想的命名空间方法示例:

SingleThing.h:

namespace single_thing   // The singleton (if this is actually valid)
{
    void GrowSomeCats(int amount); // Typical setter
    int GetNumCats();              // Typical getter
}

SingleThing.cpp:

#include "Balloon.h"

namespace // Acting like private members and functions
{   
    int numCats = 4;        // POD
    Balloon* wilson = NULL; // Not POD (and not a singleton)

    // Contrived 'private' function
    bool CanGrowCats()      
    { return wilson && wilson->LikesCats(); }

    // Contrived excuse to instantiate non-POD 'members'
    void RandomlyCreateOtherObjects()
    {
        if (!wilson /* && someRandomiserImTooLazyToType()*/ )
            wilson = new Balloon();
    }
}

namespace single_thing  // 'Public' functions
{
    void GrowSomeCats(int amount)
    {
        RandomlyCreateOtherObjects();
        if (CanGrowCats()) 
            numCats += amount;
    }

    GetNumCats()
    { return numCats; }
}

2 个答案:

答案 0 :(得分:3)

(我认为我们可以同意全球国家是一种危险的东西,必须特别小心使用。)

从技术上讲,您的单例命名空间等同于单例类。然而,它有一个主要缺点,这使得它在我看来是不行的:它隐藏了它是有状态的事实。曾经使用std::strtok()?还记得它是一个多么糟糕的混乱吗?那是因为它也隐藏了它的状态。

因为全局状态本质上是危险的,所以使用它的任何功能都应该在调用站点上清楚地表明这一事实,最好是使用语言结构 - 因为没有人阅读注释或文档。 Foo::instance()->do_work();是一种已知的模式,可以清楚地表明某些特殊情况正在发生; foo::do_work();没有。

答案 1 :(得分:0)

Singleton设计模式是关于创建有用类的唯一实例(不需要创建无用的对象)。在C ++中,类使用classstruct关键字进行定义。除了创建和销毁之外,单个类还应该实现一些与实例一起操作的方法。为了确保单一性,单例类应隐藏其构造函数并公开用于访问实例的静态方法。

仅使用名称空间,将无法定义单例的有用方法。将实例访问方法实现为命名空间中的函数而不是类本身是可能的,但是需要' friending'该函数,并没有意义,因为已经定义了类。

实现非对象单例(例如普通数据类型)将假定实例不需要构造,因此不需要单例。