私の連絡先情報
郵便メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
ソフトウェア開発では、設計パターンは、開発者がより一貫性があり、再利用可能で、保守可能な方法でソフトウェアを構築するのに役立つ、特定の問題に対する実証済みの解決策です。シングルトン パターンは、最も基本的で広く使用されている設計パターンの 1 つであり、クラスにインスタンスが 1 つだけ存在することを保証し、このインスタンスを取得するためのグローバル アクセス ポイントを提供します。この記事では、基本的な実装からスレッド セーフ バージョン、スマート ポインターや最新の C++ 機能まで、C++ でシングルトン パターンを実装する方法を詳しく説明します。std::call_once
) アプリケーションを開発し、読者に包括的で実践的なガイドを提供するよう努めています。
シングルトン パターンの中心的な考え方は、クラスにインスタンスが 1 つだけあることを保証し、グローバル アクセス ポイントを提供することです。このモードは、リソース (構成ファイル リーダー、ロガー、データベース接続プールなど) へのアクセスを制御する必要がある場合に便利です。シングルトン パターンの鍵は次のとおりです。
getInstance()
、クラスの唯一のインスタンスを取得するために使用されます。まず、スレッドの安全性の問題を考慮せずに、単純なシングルトン パターンの実装を見てみましょう。
#include <iostream>
class Singleton {
private:
// 私有构造函数,防止外部实例化
Singleton() {}
// 私有拷贝构造函数和赋值操作符,防止拷贝
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 静态实例
static Singleton* instance;
public:
// 静态方法,返回类的唯一实例
static Singleton* getInstance() {
if (!instance) {
instance = new Singleton();
}
return instance;
}
// 示例方法
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
// 析构函数(通常是protected或public,取决于是否需要外部delete)
~Singleton() {
std::cout << "Singleton destroyed." << std::endl;
}
};
// 初始化静态实例
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
s1->doSomething();
// 注意:在多线程环境下,上述实现可能存在安全问题
// 通常不推荐手动删除单例对象,除非有特别理由
// delete Singleton::instance; // 谨慎使用
return 0;
}
マルチスレッド環境では、上記の実装により複数のスレッドが同時に入る可能性があります。getInstance()
メソッドを使用してインスタンスを複数回作成します。この問題を解決するには、ミューテックス ロック (次のような) を使用できます。std::mutex
) スレッドの安全性を確保するには:
#include <mutex>
#include <iostream>
class Singleton {
private:
Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* instance;
static std::mutex mtx;
public:
static Singleton* getInstance() {
std::lock_guard<std::mutex> lock(mtx);
if (!instance) {
instance = new Singleton();
}
return instance;
}
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
~Singleton() {
std::cout << "Singleton destroyed." << std::endl;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
// main函数保持不变
シングルトン オブジェクトのライフ サイクルを自動的に管理する (つまり、プログラムの最後に自動的に破棄される) ために、スマート ポインター (次のような) を使用できます。std::unique_ptr
) 生のポインタの代わりに:
#include <memory>
#include <mutex>
#include <iostream>
class Singleton {
private:
Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static std::unique_ptr<Singleton> instance;
static std::mutex mtx;
public:
static Singleton& getInstance() {
std::lock_guard<std::mutex> lock(mtx);
if (!instance) {
instance = std::make_unique<Singleton>();
}
return *instance;
}
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
// 析构函数被智能指针管理,无需手动调用
~Singleton() {
std::cout << "Singleton destroyed." << std::endl;
}
// 禁止拷贝和移动
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
};
std::unique_ptr<Singleton> Singleton::instance = nullptr;
std::mutex Singleton::mtx;
int main() {
// 注意这里返回的是引用,无需使用指针
Singleton& s1 = Singleton::getInstance();
Singleton& s2 = Singleton::getInstance();
if (&s1 == &s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
s1.doSomething();
// 程序结束时,智能指针会自动销毁Singleton实例
return 0;
}
std::call_once
最適化C++11以降では、std::call_once
マルチスレッド環境でも関数が 1 回だけ呼び出されるようにする、より効率的かつ簡潔な方法を提供します。この機能を使用して、シングルトン パターンの実装をさらに最適化できます。
#include <memory>
#include <mutex>
#include <iostream>
#include <once.h> // 注意:实际上应使用#include <mutex>中的std::call_once
class Singleton {
private:
Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static std::unique_ptr<Singleton> instance;
static std::once_flag onceFlag;
static void createInstance() {
instance = std::make_unique<Singleton>();
}
public:
static Singleton& getInstance() {
std::call_once(onceFlag, createInstance);
return *instance;
}
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
// 析构函数和移动操作符的禁用同上
};
std::unique_ptr<Singleton> Singleton::instance = nullptr;
std::once_flag Singleton::onceFlag;
// main函数保持不变
注: 上記のコードでは、間違って引用しました。#include <once.h>
、実際に使用する必要があります<mutex>
ヘッダーファイル内でstd::once_flag
そしてstd::call_once
。
シングルトン パターンは、C++ の非常に便利な設計パターンです。これにより、クラスにインスタンスが 1 つだけ存在し、グローバル アクセス ポイントが提供されます。ただし、特にマルチスレッド環境でシングルトン パターンを実装する場合は、スレッド セーフティの問題に注意する必要があります。ミューテックスロック、スマートポインタ、std::call_once
最新の C++ 機能を使用すると、シングルトン パターンをより安全かつ効率的に実装できます。
シングルトン パターンを設計するときは、シングルトン オブジェクトのライフサイクル管理 (プログラム終了時に自動的に破棄する必要があるかどうか)、遅延読み込みが許可されているかどうか (つまり、作成を遅らせるかどうか) など、いくつかの追加要素を考慮する必要があります。最初に使用されるまでのインスタンスの)など。さらに、場合によっては、マルチインスタンス パターン (クラス インスタンスの数を制御しますが、特定の上限を超えない) やコンテキスト ベースのシングルトン パターン (異なるコンテキストに基づいて異なる値を返します)。
この記事が、読者が C++ のシングルトン パターンをより深く理解し、実際のプロジェクトで柔軟に使用できるようになれば幸いです。