Frage

leid für eine so lange Frage, aber ich versuche, so klar wie möglich zu sein. Dies ergibt sich irgendwie meine vorherige Frage zu Strings in C ++ . Ich versuche, herauszufinden, wie ich std :: string aus einer Funktion ohne redundante Speicherzuordnungen zurückkehren konnte, ohne auf NRVO verlassen . Die Gründe, warum ich will nicht auf NRVO angewiesen sind:

  • wird vom Compiler nicht unterstützt wir derzeit verwenden
  • , auch wenn es unterstützt wird, ist es vielleicht nicht immer im Debug-Modus aktiviert werden
  • könnte es in einigen Fällen fehlschlagen ( Beispiel )

Bitte beachten Sie, dass ich brauche eine C ++ 03 kompatible Lösung (keine C ++ 0x rvalue Referenzen also, leider ...)

Die einfachste Art und Weise tun, ist dieser Pass-by-reference und Sie std :: swap, wie diese

void test(std::string& res)
{
    std::string s;
    //...
    res.swap(s);
}

Aber es ist natürlicher und oft bequemer als Wert zurück als Pass Bezug genommen wird, so was will ich erreichen, ist dies:

std::string test()
{
    std::string s;
    //...
    return SOMETHING(s);
}

Im Idealfall wäre es einfach ein swap mit dem „Rückgabewert“, aber ich sehe nicht, wie dies in C ++ zu tun. Es gibt auto_ptr bereits die statt Kopie Bewegung tut, und ich konnte tatsächlich auto_ptr<string> verwenden, aber ich würde dynamisch zu vermeiden, wie sich das String-Objekt zugewiesen wird.

Meine Idee ist es, irgendwie „tag“ ein String-Objekt, dass es aus einer Funktion Genehmigung zurückgegeben wird bewegt seine Daten, wenn ein Copykonstruktor auf Rückkehr aufgerufen wird. So landete ich mit diesem Code auf, der genau das tut, was ich will:

struct Str
{
    struct Moveable
    {
        Str & ref;
        explicit Moveable(Str & other): ref(other) {}
    };

    Str() {}
    Str(const std::string& other) : data(other) {} // copy
    Str(Moveable& other) { data.swap(other.ref.data); } // move

    Moveable Move()
    {
        return Moveable(*this);
    }

    std::string data;
};

Str test()
{
    Str s;
    //...
    return s.Move(); // no allocation, even without NRVO
}

So ... Ist das alles Sinn machen, oder gibt es einige ernsthafte Probleme, dass ich vermisst habe? (Ich bin nicht sicher, ob es kein Problem Lebensdauer zum Beispiel ist). Vielleicht haben Sie bereits eine solche Idee in einer Bibliothek (Buch, Artikel ...) gesehen, und könnte einen Hinweis darauf geben Sie mir?

EDIT: Wie bemerkt @rstevens, dieser Code ist MSVC spezifisch und werden nicht unter g ++ kompilieren, die nicht wie die nicht-const vorübergehend der Fall ist. Dieses ist ein Problem, aber sich gerade diese Implementierung übernehmen ist MSVC spezifisch.

War es hilfreich?

Lösung

Die Umsetzung der Boost-Anwendungen bewegt Semantik intern Emulation für Bibliotheken wie Boost.Thread . Sie können bei der Umsetzung aussehen wollen und etwas Ähnliches tun.

Edit: gibt es eigentlich eine aktive Entwicklung einer Bibliothek Boost.Move , so können Sie bereits zu verwenden beginnen.

Andere Tipps

Haben Sie den Code überprüfen g ++?

Da Sie rufen Str (Movable &) mit einem temporären Objekt (der einen zurück von s.Move ())!

Dies ist nicht Standard-Konforme und nicht von g unterstützt ++. Es wird von MSVC unterstützt! (MS nennt dies eine Funktion, ...).

Haben Sie tatsächlich festgestellt, dass durch den Wert der Rückkehr ein Performance-Problem in der Anwendung ist? Das scheint die einfachste / einfachste Weg zu gehen, und wenn Sie auf eine modernere Compiler aktualisieren können Sie rvalue Referenzen verwenden.

Ich kann die Frage nach der Zerstörung der Reihenfolge der s Antwort gegen die Referenz des Movable. Sie könnten für den Compiler, Put-Code in den verschiedenen Konstruktoren und Destruktoren, um zu sehen, was die Ordnung ist. Auch wenn es in Ordnung aussieht würde ich immer noch als einer der normalen Mustern skizzieren Sie aber nur Leser Verwirrung zu vermeiden und möglicherweise auf einem anderen Compiler zu brechen.

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