it-swarm.com.de

Kann mir jemand eine Probe von Singleton in c ++ zur Verfügung stellen?

Ich schreibe ein Singleton-C++ auf folgende Weise:

class A {
    private:
        static A* m_pA;
        A();
        virtual ~A();

    public:
        static A* GetInstance();
        static void FreeInstance();

        void WORK1();
        void WORK2();
        void WORK3();
    }
}

A* A::GetInstance() {
    if (m_pA == NULL)
        m_pA = new A();
    return m_pA;
}

A::~A() {
    FreeInstance()  // Can I write this? are there any potential error?
}

void A::FreeInstance() {
    delete m_pA;
    m_pA = NULL;
}

Vielen Dank! Die Antwort von Evan Teran und sep61.myopenid.com ist richtig und wirklich gut! Mein Weg ist falsch, ich wünschte, jeder, der einen solchen Code schreibt, kann meinen dummen Fehler vermeiden.

Mein Singleton A in meinem Projekt hat einen Vektor eines intelligenten Zeigers, und ein anderer Thread kann diesen Vektor auch bearbeiten. Wenn die Anwendung geschlossen wird, wird sie immer instabil, selbst wenn ich viel CMutex hinzufüge. Multithread-Fehler + Singleton-Fehler verschwendete mich 1 Tag.

// ----------------------------------------- -------------- Ein neues Singleton, das Sie gerne bearbeiten können, wenn Sie der Meinung sind, dass in dem folgenden Beispiel ein Problem vorliegt:

class A {
    private:
        static A* m_pA;
        explicit A();
        void A(const A& a);
        void A(A &a);
        const A& operator=(const A& a);
        virtual ~A();

    public:
        static A* GetInstance();
        static void FreeInstance();

        void WORK1();
        void WORK2();
        void WORK3();
    }
}

A* A::GetInstance() {
    if (m_pA == NULL){
        static A self;
        m_pA = &self;
    }
    return m_pA;
}

A::~A() {
}
35
user25749

Sie können das Löschen vermeiden, indem Sie ein statisches Objekt wie das folgende verwenden:

if(m_pA == 0) {
    static A static_instance;
    m_pA = &static_instance;
}
12
Evan Teran

Warum will jeder ein Singleton als Zeiger zurückgeben?
Rückgabe als Referenz erscheint viel logischer!

Sie sollten niemals in der Lage sein, einen Singleton manuell freizugeben. Woher wissen Sie, wer einen Bezug zum Singleton hält? Wenn Sie nicht wissen (oder nicht garantieren können), dass niemand eine Referenz hat (in Ihrem Fall über einen Zeiger), dann haben Sie kein Unternehmen, das das Objekt freigibt.

Verwenden Sie die Statik in einer Funktionsmethode.
Dies garantiert, dass es nur einmal erstellt und zerstört wird. Es gibt auch eine faule Initialisierung kostenlos. 

class S
{
    public:
        static S& getInstance()
        {
            static S    instance;
            return instance;
        }
    private:
        S() {}
        S(S const&);              // Don't Implement.
        void operator=(S const&); // Don't implement
 };

Beachten Sie auch, dass Sie den Konstruktor als privat definieren müssen .. Stellen Sie außerdem sicher, dass Sie den Standardkopierkonstruktor und den Zuweisungsoperator überschreiben, damit Sie keine Kopie des Singleton erstellen können (andernfalls wäre es kein Singleton).

Lesen Sie auch:

Um sicherzustellen, dass Sie aus den richtigen Gründen ein Singleton verwenden.

Technisch nicht fadensicher im allgemeinen Fall siehe:
Wie ist die Lebensdauer einer statischen Variablen in einer C++ - Funktion?

GCC hat einen expliziten Patch, um dies zu kompensieren:
http://gcc.gnu.org/ml/gcc-patches/2004-09/msg00265.html

191
Martin York

Ein Singleton in C++ kann auf folgende Weise geschrieben werden:

static A* A::GetInstance() {
    static A sin;
    return &sin;
}
4
sep

Vergessen Sie nicht, den Kopierkonstruktor und die Zuweisungsoperatoren als privat festzulegen.

2
Jasper Bekkers

Ich glaube nicht, dass es einen Grund gibt, diese Zeile mit Nein zu schreiben. Ihre Destruktor-Methode ist nicht statisch und Ihre Singleton-Instanz wird auf diese Weise nicht zerstört. Ich denke nicht, dass der Destruktor notwendig ist, wenn Sie das Objekt bereinigen müssen, verwenden Sie die statische Methode, die Sie bereits erstellt haben, FreeInstance ().

Ansonsten erstellen Sie Ihre Singletons auf ungefähr dieselbe Weise wie ich meine.

1
Odd

Nach einer wilden Begeisterung für Singles im Meyers-Stil (mit lokalen statischen Objekten wie in einigen der vorherigen Antworten), hatte ich die lebenslangen Managementprobleme in komplizierten Apps völlig satt.

Ich neige dazu zu finden, dass Sie auf die 'Instance'-Methode absichtlich früh in der Initialisierung der App verweisen, um sicherzustellen, dass sie zu einem beliebigen Zeitpunkt erstellt wird, und dann alle Arten von Spielen mit dem Abreißvorgang aufgrund des Unvorhersehbaren (oder zumindest sehr kompliziert und etwas versteckt), in der Dinge zerstört werden.

YMMV natürlich, und es hängt ein wenig von der Art des Singleton selbst ab, aber eine Menge Waffel über clevere Singletons (und die Threading/Locking-Probleme, die die Klugheit umgeben) werden IMO überschätzt.

1
Will Dean

wenn Sie "Modernes C++ - Design" lesen, werden Sie feststellen, dass ein Singleton-Design viel komplexer sein kann, als eine statische Variable zurückzugeben. 

1
jab

Diese Implementierung ist in Ordnung, solange Sie diese Fragen beantworten können:

  1. wissen Sie, wann das Objekt erstellt wird (wenn Sie ein statisches Objekt anstelle eines neuen verwenden? Haben Sie ein main ()?)

  2. haben Sie Singleton Abhängigkeiten, die zum Zeitpunkt der Erstellung möglicherweise noch nicht bereit sind? Wenn Sie ein statisches Objekt anstelle eines neuen verwenden, welche Bibliotheken wurden zu diesem Zeitpunkt initialisiert? Was macht Ihr Objekt im Konstruktor, das sie möglicherweise erfordert?

  3. wann wird es gelöscht?

Die Verwendung von new () ist sicherer, da Sie steuern, wo und wann das Objekt erstellt und gelöscht wird. Dann müssen Sie es jedoch explizit löschen, und wahrscheinlich weiß niemand im System, wann dies geschehen soll. Sie können atexit () dafür verwenden, wenn es sinnvoll ist.

Die Verwendung eines statischen Objekts in einer Methode bedeutet, dass nicht genau bekannt ist, wann es erstellt oder gelöscht wird. Sie könnten auch ein globales statisches Objekt in einem Namespace verwenden und getInstance () überhaupt vermeiden - es fügt nicht viel hinzu.

Wenn Sie Threads verwenden, haben Sie große Probleme. Es ist praktisch unmöglich, in C++ ein brauchbares Thread-sicheres Singleton zu erstellen, weil

  1. permanente Sperre in getInstance ist sehr umfangreich - ein vollständiger Kontextwechsel bei jedem getInstance ()
  2. eine doppelt geprüfte Sperre schlägt aufgrund von Compiler-Optimierungen und eines Cache-/schwachen Speichermodells fehl, ist sehr schwierig zu implementieren und kann nicht getestet werden. Ich würde nicht versuchen, dies in einem realen System zu tun, es sei denn, Sie kennen Ihre Architektur genau und wollen, dass sie nicht portabel ist

Diese lassen sich leicht googeln, aber hier ist ein guter Link zu einem schwachen Speichermodell: http://ridiculousfish.com/blog/archives/2007/02/17/barrier .

Eine Lösung wäre, Sperren zu verwenden, aber die Benutzer müssen den Zeiger zwischenspeichern, den sie von getInctance () erhalten, und darauf vorbereitet sein, dass getInstance () schwer ist.

Eine andere Lösung wäre, den Benutzern die Thread-Sicherheit selbst zu ermöglichen.

Eine andere Lösung wäre, eine Funktion mit einfacher Verriegelung zu verwenden und sie durch eine andere Funktion zu ersetzen, ohne dass das Aufrufen von new () gesperrt und überprüft wird. Dies funktioniert, aber die vollständige Implementierung ist kompliziert.

0
n-alexander
//! @file singleton.h
//!
//! @brief Variadic template to make a singleton out of an ordinary type.
//!
//! This template makes a singleton out of a type without a default
//! constructor.

#ifndef SINGLETON_H
#define SINGLETON_H

#include <stdexcept>

template <typename C, typename ...Args>
class singleton
{
private:
  singleton() = default;
  static C* m_instance;

public:
  singleton(const singleton&) = delete;
  singleton& operator=(const singleton&) = delete;
  singleton(singleton&&) = delete;
  singleton& operator=(singleton&&) = delete;

  ~singleton()
  {
    delete m_instance;
    m_instance = nullptr;
  }

  static C& create(Args...args)
  {
    if (m_instance != nullptr)
      {
    delete m_instance;
    m_instance = nullptr;
      }
    m_instance = new C(args...);
    return *m_instance;
  }

  static C& instance()
  {
    if (m_instance == nullptr)
      throw std::logic_error(
        "singleton<>::create(...) must precede singleton<>::instance()");
    return *m_instance;
  }
};

template <typename C, typename ...Args>
C* singleton<C, Args...>::m_instance = nullptr;

#endif // SINGLETON_H
0
amightywind

Es gibt eine großartige C++ - Bibliothek, ACE, die auf Mustern basiert. Es gibt viele Dokumentationen über verschiedene Arten von Mustern, also schauen Sie sich ihre Arbeit an: http://www.cs.wustl.edu/~schmidt/ACE.html

0