我已经看到了Singleton模式的实现,其中实例变量在GetInstance方法中被声明为静态变量.像这样:
SomeBaseClass &SomeClass::GetInstance()
{
static SomeClass instance;
return instance;
}
Run Code Online (Sandbox Code Playgroud)
我认为这种方法有以下积极方面:
这种方法的不利方面是什么(除了这不是非常OOP-ish)?这是线程安全的吗?
我已经在网上阅读了很多帖子和文章,但我找不到明确的答案.
我有一些具有类似用途的功能,我想要超出全局范围.其中一些需要公开,另一些应该是私有的(因为它们只是"公共"功能的辅助功能).另外,我不仅有函数,还有变量.它们只需要"私人"帮助函数,也应该是私有的.
现在有三种方式:
对我采取什么方式?结合其中一些方法的可能方法?
我想到了类似的东西:
谢谢.
请考虑以下代码:
#include <iostream>
struct A
{
A(){ };
~A(){ std::cout << "~A::A()" << std::endl; };
};
struct B: A { };
B *b = new B; //Doesn't produce any side-effect.
int main(){ }
Run Code Online (Sandbox Code Playgroud)
程序不会产生任何输出,这意味着不会调用析构函数.但是如果我们用说明delete符替换析构函数的主体,程序甚至不会编译.
#include <iostream>
struct A
{
A(){ };
~A() = delete; //{ std::cout << "~A::A()" << std::endl; };
};
struct B: A { };
B *b = new B; //Error: use of deleted function
int main(){ }
Run Code Online (Sandbox Code Playgroud)
由于调用了删除的功能.那是在这种情况下被调用的析构函数.为什么会有这样的差异?
即使我们明确定义了B构造函数,它也不会起作用:
#include <iostream> …Run Code Online (Sandbox Code Playgroud) 编辑:对不起,我的问题不明确,为什么书籍/文章更喜欢实施#1而不是实施#2?
使用指针实现Singleton类与使用静态对象的实际优势是什么?为什么大多数书都喜欢这个
class Singleton
{
private:
static Singleton *p_inst;
Singleton();
public:
static Singleton * instance()
{
if (!p_inst)
{
p_inst = new Singleton();
}
return p_inst;
}
};
Run Code Online (Sandbox Code Playgroud)
在此
class Singleton
{
public:
static Singleton& Instance()
{
static Singleton inst;
return inst;
}
protected:
Singleton(); // Prevent construction
Singleton(const Singleton&); // Prevent construction by copying
Singleton& operator=(const Singleton&); // Prevent assignment
~Singleton(); // Prevent unwanted destruction
};
Run Code Online (Sandbox Code Playgroud) 来自Java背景,对我来说,处理创建类的选择或者只是实现我可能需要的函数是新的.通常,在建模可能具有状态的东西时,这是毫无疑问的.
现在我正在实现一个没有main函数和静态成员函数的共享库.是否有些东西反对创建一个类来封装函数?
此外,我想在另一个文件中封装更多代码,尤其是辅助功能.执行代码总是相同的,并且它的状态不会改变,所以我想我会声明它们也是静态的 - 所以这里出现了同样的问题.
在Jon的网站上,他在C#中使用了这个优雅设计的单例,如下所示:
public sealed class Singleton
{
Singleton()
{
}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道如何在C++中编写等效代码?我有这个,但我不确定它是否实际上具有与Jon相同的功能.(顺便说一下,这只是一个星期五的练习,不需要任何特别的东西).
class Nested;
class Singleton
{
public:
Singleton() {;}
static Singleton& Instance() { return Nested::instance(); }
class Nested
{
public:
Nested() {;}
static Singleton& instance() { …Run Code Online (Sandbox Code Playgroud) 因此,经典简单的Singleton实现如下:
class Singleton
{
private:
static Singleton* singleton;
Singleton() {}
public:
static Singleton* getInstance();
};
Run Code Online (Sandbox Code Playgroud)
cpp文件:
Singleton* Singleton::singleton = 0;
Singleton* Singleton::getInstance()
{
if (!singleton)
{
singleton = new Singleton;
}
return singleton;
}
Run Code Online (Sandbox Code Playgroud)
我在这里看到的内存泄漏- "因为没有删除的新.但是在C++中没有静态析构函数,所以我们只是不关心这个内存泄漏?
我正在通过进行小型机器人模拟来学习C++,而我在类中的静态成员函数方面遇到了麻烦.
我的环境类定义如下:
class Environment {
private:
int numOfRobots;
int numOfObstacles;
static void display(); // Displays all initialized objects on the screen
public:
Robot *robots;
Obstacle *obstacles;
// constructor
Environment();
static void processKeySpecialUp(int, int, int); // Processes the keyboard events
};
Run Code Online (Sandbox Code Playgroud)
然后在构造函数中我初始化机器人和障碍物,如下所示:
numOfRobots = 1; // How many robots to draw
numOfObstacles = 1;
robots = new Robot[numOfRobots];
obstacles = new Obstacle[numOfObstacles];
Run Code Online (Sandbox Code Playgroud)
以下是使用这些变量的静态函数示例:
void Environment::display(void) {
// Draw all robots
for (int i=0; i<numOfRobots; i++) {
robots[i].draw();
}
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译时,我会收到类似的错误消息
error: …Run Code Online (Sandbox Code Playgroud) 我正在使用传统的C API,在这种API下获取一些资源是昂贵的,并且释放该资源绝对是至关重要的.我正在使用C++ 14,我想创建一个类来管理这些资源.这是事物的基本骨架......
class Thing
{
private:
void* _legacy;
public:
void Operation1(...);
int Operation2(...);
string Operation3(...);
private:
Thing(void* legacy) :
_legacy(legacy)
{
}
};
Run Code Online (Sandbox Code Playgroud)
这不是单身模式.没有什么是静态的,可能有很多Thing实例,都在管理自己的遗留资源.此外,这不仅仅是一个智能指针.包裹的指针,_legacy是私有的,所有操作都是通过一些公共实例函数公开的,这些函数隐藏了消费者的遗留API.
构造函数是私有的,因为实例将从实际获取资源Thing的静态工厂或命名构造函数返回.这是对该工厂的廉价模仿,使用malloc()作为代码的占位符来调用遗留API ...
public:
static Thing Acquire()
{
// Do many things to acquire the thing via the legacy API
void* legacy = malloc(16);
// Return a constructed thing
return Thing(legacy);
}
Run Code Online (Sandbox Code Playgroud)
这是析构函数,它负责释放遗留资源,同样,free()它只是一个占位符......
~Thing() noexcept
{
if (nullptr != _legacy)
{
// Do many …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
MyType x = do_something_dangerous();
// ...
if (some_condition) {
// ...
bar(x);
}
else {
// ...
}
// ...
if (another_condition_which_may_depend_on_previous_if_else} {
// ...
baz(x);
}
Run Code Online (Sandbox Code Playgroud)
这个想法是,在某些情况下,我可能需要使用,这可能是事先确定的难度/不方便x.但是在我不需要使用它的情况下,尝试初始化它可能是不好的(比如说,可能会导致我的进程崩溃).
现在,似乎我需要使用的是一个初始化按需持有者(链接侧重于Java,所以这里是一个草图):某种Wrapper<MyType>或Wrapper<MyType, do_something_dangerous>一种get()方法,这样第一次get()调用do_something_dangerous(),后来get()只是通过第一次通话获得的价值.
笔记:
boost::optional,但这有点麻烦,也扭曲了预期的用途:"建议optional<T>在没有类型的价值,T缺乏的地方,只有一个,清楚(对所有各方)的原因使用价值与任何常规价值一样自然T."c++ ×10
singleton ×5
static ×3
c++11 ×2
c# ×1
c++14 ×1
constructor ×1
destructor ×1
idiomatic ×1
idioms ×1
move ×1
namespaces ×1