Frage

Oft füge ich ein Empty Methode, um meine C ++ Objekte, um den internen Zustand löschen Verwendung von Code ähnlich dem folgenden.

class Foo
{
private:
    int n_;
    std::string str_;
public:
    Foo() : n_(1234), str_("Hello, world!")
    {
    }

    void Empty()
    {
        *this = Foo();
    }
};

Das scheint besser zu sein als Code im Konstruktor duplizieren, aber ich fragte mich, ob *this = Foo() ein gemeinsamer Ansatz ist zu wollen, wenn ein Objekt löschen? Gibt es irgendwelche Probleme mit diesem Warten, mich zu beißen auf der Rückseite? Gibt es noch andere bessere Möglichkeiten, diese Art der Sache zu erreichen?

War es hilfreich?

Lösung

ich lasse der Konstruktor meine Funktion aufrufen statt:

class Foo
{
private:
    int n_;
    std::string str_;
public:
    Foo()
    {
        Reset();
    }

    void Reset()
    {
        n_ = 1234;
        str_ = "Hello, world!";
    }
};

Ja, ich ist unnötig die Zeichenfolge als eine leere Zeichenfolge initialisiert wird zuerst, dann eine Zuordnung zu tun, aber das ist viel klarer.

Andere Tipps

Mögliche Probleme? Woher wissen Sie, dass * das ist wirklich ein Foo?

Was Sie mit dieser Leeren Methode tun, ist im Wesentlichen der gleiche wie manuell ein neu konstruiertes Objekt auf eine Variable (die Sache, dass die Leere Funktion des Fall ist) zugewiesen wird.

Ich persönlich würde die Leere Methode entfernen und ersetzen alle Anwendungen dieses Verfahrens mit diesem:

// let's say, that you have variables foo and pfoo - they are properly initialized.
Foo foo, *pfoo;

// replace line "foo.Empty()" with:
foo = Foo();

// replace line "pfoo->Empty()" with:
delete pfoo;
pfoo = new Foo();
// or
*pfoo = Foo();

Ich sehe keinen Vorteil wirklich diese Leere Methode zu haben. Es verbirgt, was wirklich auf das Objekt auf Hexe geschieht es heißt, der Name ist nicht die beste Wahl, entweder.

Wenn der Anrufer wirklich ein sauberes Objekt will -. Er wird kein Problem das sich Objekt konstruieren hat

Bedenken Sie auch Objekte unveränderlich zu machen, d. , wenn gebaut, können sie nicht mehr geändert werden. Dies kann in vielen Szenarien sparen Sie sich von unerwarteten Nebenwirkungen.

Es gibt etwas, noch häufiger als das, was Sie vorgeschlagen haben. mit Swap.

Im Grunde Sie etwas tun, wie folgt aus:

T().swap(*this);

da viele Standardcontainer (alle der STL-Container?), Eine konstante Zeit Swap-Methode haben, ist dies eine schöne und einfache Art und Weise einen Behälter zu löschen und sicherzustellen, dass es Speicher ist freigegeben wird.

Und es ist ein guter Weg, um „shrink to fit“ als auch einen Behälter, aber die Kopie Konstruktor anstelle des Standard-Konstruktor.

betrachten Platzierung new mit:

void Empty() {
    this->~Foo();
    new (this) Foo();
}

Der Code ruft operator =, die für alle Arten von Nebenwirkungen führen kann.

Bearbeiten in Reaktion auf die Kommentare. - Dieser Code ist auf jeden Fall gut definiert, die Standard ausdrücklich zulässt. Ich werde den Absatz später schreiben, wenn ich die Zeit finden. Über delete - natürlich. Was ich meinte ~Foo() wurde, war dies ein Versehen. Und ja, Rob ist rechts als auch, zerstörend das Objekt hier tatsächlich notwendig ist, die Zeichenfolge des destructor zu nennen.

Dies kann eine potentielle Quelle für Speicherverlust, wenn Sie einen dynamisch zugewiesenen Speicher im Konstruktor haben.

Hier ist, wie ich es tun:

class Foo {
private:
    int n_;
    std::string str_;
public:
    Foo() : n_(1234), str_("Hello, world!")
    {
    }

    void Empty()
    {
        Foo f;
        swap(f);
    }

    void swap(Foo & other) {
        std::swap(n_, other.n_);
        swap(str_, other.str_);
    }
};

void swap(Foo & one, Foo & other) {
    one.swap(other);
}

Setzen Sie die Swap-Funktion in den gleichen Namensraum wie die Foo-Klasse. Argument abhängiger Lookup findet es, wenn der Benutzer einen Anruf zu tun tauschen zwei Foo zu tauschen. Sie können auch operator= mit Swap-Funktion implementieren.

  

Das scheint besser zu sein als Code im Konstruktor duplizieren, aber ich fragte mich, ob * diese Foo = () ist ein gemeinsames Konzept zu wollen, wenn ein Objekt löschen?

Löschen ein Objekt ist nicht so häufig eine Sache zu tun. Häufiger, entweder ein Objekt (vielleicht sogar ein unveränderliches Objekt) instanziiert und enthält reale Daten, oder es wird nicht instanziiert

Die häufigste Art der Sache, dass sind Reset-Container wäre ... aber, würden Sie nicht Ihre eigene Containerklassen jetzt schreiben, würden Sie.

  

Gibt es irgendwelche Probleme mit dieser Warte mich auf der Rückseite zu beißen?

Ja:

  • Ist dies nicht wirklich ein Foo sondern ein DerivedFoo
  • Wenn Foo des Zuweisungsoperator nicht existiert, oder wenn es Buggy ist (zum Beispiel, wenn es nicht definiert ist und der Standardoperator ist nicht gut, beispielsweise aufgrund eines Datenelementes ist ein nackter Zeiger).
  

Gibt es andere bessere Möglichkeiten, diese Art der Sache zu erreichen?

Ja, vielleicht eine freie Funktion wäre besser (würde vermieden, sowohl die oben genannten Probleme):

template<class T> void reconstruct(T* p)
{
    p->~T();
    new (p) T();
}

Ja, das ist nicht effizient in Bezug auf Leistung (Schaffung einer anderen foo Objekt, anstatt zu arbeiten in place) und es wird Sie beißen, wenn Sie Speicher im Konstruktor mit einem bösen Speicherleck zuteilen würde.

So dass es sicherer in Bezug auf Speicher aufrufen würde die this-> löschen und diese = new foo () -. Aber es wird SLOW

Wenn Sie ein statisches leeres Objektfeld super erstellen sein und MEMCPY es im Reset.

Wenn Sie die Eigenschaften eines nach dem anderen nur schnell zuordnen können.

Wenn Sie wollen, ohne Reset-Duplizierung Anruf angemessenen Stil halten von Ctor als Ates Goral vorgeschlagen, aber Sie werden den schnelleren Aufbau mit dem Standard params verlieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top