带参考变量的Singleton

Singleton with Reference Variable

本文关键字:Singleton 变量 参考      更新时间:2023-10-16

我需要几个唯一的对象,这些对象在程序运行时总是可用的。我遵循Singleton设计模式,它建议使用方法getInstance()来获取对象。但我更喜欢在不调用方法的情况下立即检索对象。所以我写了一个类,它提供了几个由引用类型而不是指针返回的唯一对象。

class Priority
{
public:
static Priority &High;
static Priority &Medium;
static Priority &Low;
std::string getName(void);
int getLevel(void);
private:
Priority(int level, std::string const& name);
~Priority();
Priority(Priority const&);
const Priority &operator = (Priority const&);
int level_;
std::string name_;
};
Priority &Priority::High   = Priority(3, "High");
Priority &Priority::Medium = Priority(2, "Medium");
Priority &Priority::Low    = Priority(1, "Low");
Priority::Priority(int level, std::string const& name)
: level_(level), name_(name)
{ }
Priority::~Priority() { }
inline std::string Priority::getName(void)
{
return name_;
}
inline int Priority::getLevel(void)
{
return level_;
}


我编写了一个使用上述类的示例程序。

int main()
{
Priority &m = Priority::High;
std::string name = m.getName();
int level = m.getLevel();
return 0;
}


程序运行良好。因此,我假设为变量分配的内存在程序停止或卸载存储类的dll文件之前,Priority &Priority::High = Priority(3, "High");不会被擦除。我说得对吗?

问题

您展示的代码不应该编译:您不能将对非const的引用绑定到右值。

Visual C++11.0和g++4.7.1:示例

[D:\dev\test]>cl foo.cppfoo.cppfoo.cpp(27):警告C4239:使用了非标准扩展:"initializing":从"Priority"转换为"Priority&"非常数引用只能绑定到左值foo.cpp(28):警告C4239:使用了非标准扩展:"initializing":从"Priority"转换为"Priority&"非常数引用只能绑定到左值foo.cpp(29):警告C4239:使用了非标准扩展:"initializing":从"Priority"转换为"Priority&"非常数引用只能绑定到左值[D:\dev\test]>gnuc foo.cppfoo.cpp:27:48:错误:从"Priority"类型的右值初始化"Priority&"类型的非常量引用无效foo.cpp:28:50:error:从"Priority"类型的右值初始化"Priority&"类型的非常量引用无效foo.cpp:29:47:错误:从"Priority"类型的右值初始化"Priority&"类型的非常量引用无效[D:\dev\test]>_

工具使用

对于Visual C++,请使用选项/W4(警告级别4)来获得上面显示的警告。

您可以将此和其他“使其符合标准";环境变量CL中的选项(与Microsoft链接器的LINK相同,例如/entry:mainCRTStartup作为默认链接器选项)。

[D:\dev\test]>echo%CL%/nologo/EHsc/GR/W4/FI"prolock/cppx/macro/c++11.for_msvc_11.h"[D:\dev\test]>_

C++修复该问题

您可以使用右值引用来代替左值引用,但是尽管Visual C++对此很满意,g++还是抱怨了私有析构函数。

因此,在参考思想的指导下–它的目的是什么–您可以简单地使用普通的静态数据成员。

然而,对于普通的静态数据成员,而不是Meyers的singleton,您可能会遇到静态初始化顺序失败的风险。因此,如果您绝对必须提供全局,我建议使用singleton。至于singleton的类型,使用最简单的解决方案通常是最好的,这意味着Meyers的singleton(我刚刚链接了第一个看起来合理的谷歌结果)。

这甚至不应该编译,您正在用临时对象初始化引用。然而,你根本不需要那里的参考资料;只需直接将静态成员声明为对象:

在标题中:

class Priority
{
public:
static Priority High;
static Priority Medium;
static Priority Low;
//...
};

在源文件中:

Priority Priority::High(3, "High");
Priority Priority::Medium(2, "Medium");
Priority Priority::Low(1, "Low");