τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Στην ανάπτυξη λογισμικού, τα πρότυπα σχεδίασης είναι αποδεδειγμένες λύσεις σε συγκεκριμένα προβλήματα. Βοηθούν τους προγραμματιστές να δημιουργήσουν λογισμικό με πιο συνεπή, επαναχρησιμοποιήσιμο και συντηρήσιμο τρόπο. Το Singleton Pattern είναι ένα από τα πιο βασικά και ευρέως χρησιμοποιούμενα μοτίβα σχεδίασης Διασφαλίζει ότι μια κλάση έχει μόνο μία παρουσία και παρέχει ένα παγκόσμιο σημείο πρόσβασης για την απόκτηση αυτής της παρουσίας.Αυτό το άρθρο θα εξετάσει σε βάθος πώς να εφαρμόσετε το μοτίβο Singleton στη C++, από τη βασική υλοποίηση έως τις εκδόσεις που είναι ασφαλείς για νήμα έως τις σύγχρονες λειτουργίες της C++, όπως έξυπνους δείκτες καιstd::call_once
) εφαρμογή και προσπαθούν να παρέχουν στους αναγνώστες έναν περιεκτικό και πρακτικό οδηγό.
Η βασική ιδέα του μοτίβου singleton είναι να διασφαλίσει ότι μια κλάση έχει μόνο μία παρουσία και παρέχει ένα παγκόσμιο σημείο πρόσβασης. Αυτή η λειτουργία είναι χρήσιμη όταν χρειάζεται να ελέγχετε την πρόσβαση σε πόρους (όπως προγράμματα ανάγνωσης αρχείων διαμόρφωσης, καταγραφείς, ομάδες σύνδεσης βάσεων δεδομένων, κ.λπ.). Το κλειδί για το μοτίβο singleton είναι:
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()
μέθοδο και δημιουργία παρουσιών πολλές φορές.Για να λύσουμε αυτό το πρόβλημα, μπορούμε να χρησιμοποιήσουμε μια κλειδαριά mutex (όπως π.χ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函数保持不变
Προκειμένου να διαχειριστούμε αυτόματα τον κύκλο ζωής ενός αντικειμένου singleton (δηλαδή που καταστρέφεται αυτόματα στο τέλος του προγράμματος), μπορούμε να χρησιμοποιήσουμε έξυπνους δείκτες (όπως π.χ.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
Παρέχει έναν πιο αποτελεσματικό και συνοπτικό τρόπο για να διασφαλιστεί ότι μια συνάρτηση καλείται μόνο μία φορά, ακόμη και σε περιβάλλον πολλαπλών νημάτων. Μπορούμε να χρησιμοποιήσουμε αυτή τη δυνατότητα για να βελτιστοποιήσουμε περαιτέρω την υλοποίηση του μοτίβου singleton:
#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
。
Το μοτίβο singleton είναι ένα πολύ χρήσιμο μοτίβο σχεδίασης στη C++ Διασφαλίζει ότι μια κλάση έχει μόνο μία παρουσία και παρέχει ένα παγκόσμιο σημείο πρόσβασης. Ωστόσο, πρέπει να δώσετε προσοχή σε ζητήματα ασφάλειας νημάτων κατά την εφαρμογή του μοτίβου singleton, ειδικά σε περιβάλλον πολλαπλών νημάτων.Χρησιμοποιώντας κλειδαριές mutex, έξυπνους δείκτες καιstd::call_once
Με τις σύγχρονες δυνατότητες C++, μπορούμε να εφαρμόσουμε το μοτίβο singleton με μεγαλύτερη ασφάλεια και αποτελεσματικότητα.
Όταν σχεδιάζετε το μοτίβο singleton, πρέπει να λάβετε υπόψη ορισμένους πρόσθετους παράγοντες, όπως τη διαχείριση του κύκλου ζωής του αντικειμένου singleton (αν πρέπει να καταστραφεί αυτόματα όταν τελειώσει το πρόγραμμα), εάν επιτρέπεται η τεμπέλικη φόρτωση (δηλαδή η καθυστέρηση της δημιουργίας μιας περίπτωσης μέχρι να χρησιμοποιηθεί για πρώτη φορά) κ.λπ. Επιπλέον, σε ορισμένες περιπτώσεις, μπορεί να θέλετε να εξετάσετε παραλλαγές του μονότονου μοτίβου, όπως το μοτίβο πολλαπλών περιπτώσεων (το οποίο ελέγχει τον αριθμό των παρουσιών κλάσης, αλλά δεν υπερβαίνει ένα ορισμένο ανώτατο όριο) ή το μοτίβο μονής γραμμής που βασίζεται στο περιβάλλον ( που επιστρέφει διαφορετικές τιμές με βάση διαφορετικά περιβάλλοντα).
Ελπίζω ότι αυτό το άρθρο μπορεί να βοηθήσει τους αναγνώστες να κατανοήσουν καλύτερα το μοτίβο singleton στη C++ και να το χρησιμοποιήσουν με ευελιξία σε πραγματικά έργα.