c++ - 为什么我的单例实现不能编译?(C++)
问题描述
我是 C/C++ 新手
我试图实现单例模式。
为什么不遵循代码无法编译。在 javascript 中,以类似的方式实现单例模式没有问题。(https://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript)
我认为当我声明指针时*singleton_instance
static
,它可以通过静态方法访问。但是 G++ 给出了错误
singleton_pattern_nullptr.cpp:12:20: warning: ‘constexpr’ needed for in-class initialization of static data member ‘Grammar* Grammar::singleton_instance’ of non-integral type [-fpermissive]
12 | static Grammar *singleton_instance = NULL;
但即使有
#include <iostream>
#include <stdio.h>
#define NULL nullptr
class Grammar {
protected:
Grammar() {};
Grammar(const Grammar&) = delete;
Grammar& operator=(const Grammar&) = delete;
static Grammar *singleton_instance = NULL;
public:
Grammar& getInstance();
};
static Grammar& Grammar::getInstance() {
if(singleton_instance == NULL) {
// no star with new
singleton_instance = new Grammar();
}
return *singleton_instance;
}
int main(int argc, char* argv[]) {
Grammar *grammar;
grammar = Grammar::getInstance();
return 0;
}
现在当我定义
static constexpr Grammar *singleton_instance = NULL;
g ++产生错误消息...
singleton_pattern_nullptr.cpp:23:23: error: assignment of read-only variable ‘Grammar::singleton_instance’
23 | singleton_instance = new Grammar();
还是 ...
singleton_pattern_nullptr.cpp:33:34: error: cannot call member function ‘Grammar& Grammar::getInstance()’ without object
33 | grammar = Grammar::getInstance();
我以为我可以做到,mutable
但在这个线程中(C++ 中的静态可变成员变量?)我读到不需要指定静态成员变量才能成为mutable
(可变),因为这应该已经是无论如何。
所以请告诉我我的错误在哪里,以及在 C++ 中是否可以实现我上面想到的单例(参见 javascript 示例)。
谢谢
编辑:
在承认了目前的答案之后,我仍然无法判断我做错了什么。请告诉我如何更改定义指针*singleton_instance
,Grammar::getInstance()
以便我可以根据想法操作指针,如果可能的话。我现在沮丧地声明了静态,并根据 g++ 的错误消息用*singleton_instance
修饰符声明。constexpr
不会那么难吧?
另一个例子:https ://developer-blog.net/singleton-design-pattern-in-c/
谢谢
编辑2:
感谢M47发布有效的“Meyers Singleton”(用户idclev 463035818注释)
但是,尽管我设置了标志-std=c++17
,编译器仍然会以警告响应
**singleton_pattern.h:9:12:** warning: inline variables are only available with ‘-std=c++17’ or ‘-std=gnu++17’
9 | static inline Grammar *singleton_instance = nullptr;
但是请允许我提出三个(两个?)关于 c++ 的更多理解问题。
1 - 在头文件中,方法声明为static inline
static inline Grammar *singleton_instance = nullptr;
但是,在定义中,您传递了这些“修饰符” (?)。或者是通过命名空间/类操作符在定义中隐含一个static
或两个?我想我在某处读过类似的东西。static inline
::
Grammar& Grammar::getInstance()
如果不是这样,那么我知道头文件声明和 cpp 文件定义中的分歧修饰符上有线程。你能给我一个提示吗?
最后但并非最不重要的(小问题)我收到警告
warning: variable ‘grammar’ set but not used [-Wunused-but-set-variable]
非常感谢您向我展示了如何使单例模式的指针版本工作!赞!
解决方案
无需将静态实例显式声明为成员变量。你也可以这样做:
class Grammar
{
public:
Grammar() {}
Grammar(const Grammar&) = delete;
Grammar& operator=(const Grammar&) = delete;
static Grammar& Grammar::getInstance() {
static Grammar instance;
return instance
}
};
这样,您还可以避免直接使用原始指针、潜在的分段错误和 SIOF。话虽如此,根据C++ 核心指南不推荐使用单例范式。
请注意,我已经删除了前两行中的复制构造函数和赋值。这通常在单例范式中完成,以避免不需要的副本。
编辑:用指针做
// header file:
class Grammar {
protected:
Grammar() {};
Grammar(const Grammar&) = delete;
Grammar& operator=(const Grammar&) = delete;
static inline Grammar *singleton_instance = nullptr;
public:
static Grammar& getInstance();
};
// cpp file
Grammar& Grammar::getInstance() {
if (singleton_instance == nullptr) {
// no star with new
singleton_instance = new Grammar();
}
return *singleton_instance;
}
// main.cpp
#include "grammar.h"
int main(int argc, char* argv[]) {
Grammar *grammar;
grammar = &Grammar::getInstance();
return 0;
}
静态内联成员变量仅在 C++17 中定义。另一种方法是在类外初始化静态成员。它必须在一个且只有一个翻译单元中完成。这可能会导致 SIOF:
// cpp file
#include "grammar.h"
Grammar* Grammar::singleton_instance = nullptr;
...
推荐阅读
- python - Numpy 和 Matplotlib,使用 imshow 或 pcolor 打印矩阵问题
- java - 如何在 kotlin 中为此 { "words":[3,4,5] } json 创建数据模型
- javascript - 有什么方法可以在 html 中显示输入栏?
- php - 将图像在屏幕上显示时的宽度存储在 PHP 会话变量中
- asp.net-core - ASP.NET Core 3.1:使用带有视图模型的存储过程
- postgresql - PostgreSQL 中不允许将显式空值传递给标识列吗?
- sql - 无法找出准确的查询来获取我的报告的时间戳
- function - 如何将其转换为 OOP 结构?
- arrays - 在 Angular 中使用 2 个带有 Map 函数的数组创建新数组
- go - 使用 gin 和 gorm 在 go lang 中对创建和更新操作使用相同的结构