2017-02-16 13 views
-1

Ich mache ein Framework, das eine XML-Datei Tiled lesen wird und das resultierende Objekt (tpp :: File) wird unveränderlich (keine Setter oder Kopie Konstruktoren/Zuweisungsoperatoren). Im Grunde verwendet es die builder pattern Idee, aber anstatt 2 Objekte mit den gleichen Attributen zu haben, werde ich eins mit den Hauptattributen haben und ein anderes, das es "wickeln" wird.Unveränderliche Klassen und Kopierkonstruktoren

// Represents a Tiled's TMX file. This object is immutable. 
class TILEDPP_API File final 
{ 
public: 
    File() = default; 
    File(tpp::File&&) = default; 
    File(const tpp::File&) = delete; 
    File(const tpp::Path& path, tpp::FileMetadata& metadata); 

    File& operator = (tpp::File&&) = default; 
    File& operator = (const tpp::File&) = delete; 

    const tpp::Path& getPath() const; 
    const tpp::Header& getHeader() const; 
    const tpp::Layers& getLayers() const; 
    const tpp::TileSets& getTileSets() const; 

private: 
    const tpp::Path m_path; 
    tpp::FileMetadata m_metadata; // Should be const! 
}; 

// Represents the content of a Tiled's TMX file (header, sets, layers etc). 
// This struct is non-copyable due to its HUGE size. 
struct TILEDPP_API FileMetadata final 
{ 
    FileMetadata() = default; 
    FileMetadata(tpp::FileMetadata&&) = default; 
    FileMetadata(const tpp::FileMetadata&) = delete; 

    FileMetadata& operator = (FileMetadata&&) = default; 
    FileMetadata& operator = (const FileMetadata&) = delete; 

    tpp::Header header; 
    tpp::Layers layers; 
    tpp::TileSets sets; 
}; 

Dann irgendwo in der Datei Erstellungsprozess, werden wir dieses:

tpp::File FileReader::read(const std::string& path) 
{ 
    tpp::FileMetadata metadata = m_parser.parseMetadata(path); 

    return tpp::File(path, metadata); 
} 

Die obige Snippet den File(const tpp::Path& path, tpp::FileMetadata& metadata) Konstruktor wird, wie erwartet. Jedoch, wenn wir tpp :: File tpp :: FileMetadata const machen, wird es versuchen, stattdessen den File(const tpp::File&) Konstruktor zu verwenden, der gelöscht ist. Warum passiert es überhaupt ?!

Als Referenz kann das Projekt here gefunden werden. Alle Gedanken werden auch sehr geschätzt.

Antwort

0

es versuchen wird, den File(const tpp::File&) Konstruktor zu verwenden, anstatt

ist stattdessen das falsche Wort.

Ebenso ist das richtige Wort.

Vor C++ 17 erstellen Sie ein temporäres File und geben eine move-constructed Kopie von der Funktion zurück. (Diese Move-Konstruktion kann weggelassen werden, und in C++ 17 wird keine Kopie mehr konstruiert).

FileMetaData unterstützt keinen Umzug von FileMetadata const&&). So funktioniert Ihre in File(File&&) nicht; Keine Standardimplementierung kann funktionieren.


Objekte können nicht sowohl unveränderlich als auch praktisch beweglich sein.

Unveränderliche Objekte können praktisch nicht verschoben werden - aus C++; während sie während der Zerstörung unveränderlich sind, geschieht die Verschiebung von vor der Zerstörung, wenn sie unveränderlich sein müssen. Sie können also ihren Zustand nicht "ausreißen" und ihn woanders hinbewegen.

Ich erkläre dies, weil Sie scheinen wollen Einzug von unterstützen:

File(tpp::File&&) = default; 
File& operator = (tpp::File&&) = default; 

Wenn Sie von move-wollen, Filekann nicht unveränderlich sein. Wenn Sie unveränderlich möchten, kann File nicht verschoben werden.

Angenommen, Sie möchten die Unveränderlichkeit beibehalten.


Stellen jene =delete, dann

ändern
return tpp::File(path, metadata) 

zu

return {std::move(path), std::move(metadata)}; 

und

File(const tpp::Path& path, tpp::FileMetadata& metadata); 

zu

ändern
File(tpp::Path&& path, tpp::FileMetadata&& metadata); 

und Ihr Code kompiliert.

read aufzurufen, speichern den Rückgabewert in einem File&& oder ein auto&& - ein rvalue Bezug auf die vorübergehende read zurückkehrt.

Hinweis: Sie können diese zurückgegebene File nicht in einer Variable mit einer längeren Lebensdauer speichern, da dies den Wechsel von File erfordert, die unveränderliche Objekte nicht zulassen.


Alternativ, zurück auf Unveränderlichkeit. Machen Sie es unveränderlich mit Ausnahme des Umzugs.

Objekte, die unveränderlich sind außer Verschieben speichern ihre Daten nicht als const, weil sie es mutieren, wenn sie sich bewegen. Jede andere Methode auf ihnen ist const.

+0

Hallo, @Yakk! Danke für deine Antwort! Könnten Sie mich bitte aufklären: 'FileMetaData unterstützt keine Verschiebung von FileMetadata const &&). So funktioniert Ihr = Standard in Datei (Datei &&) nicht; keine Standardimplementierung kann funktionieren. Wie fügt "Unterstützung hinzufügen" für move-from hinzu, dass * der Move-Konstruktor/-Assigment-Operator * gelöscht * wird? –

+0

@YvesHenri Wo hast du "Unterstützung hinzufügen" gesehen? Wen zitierst du? Dein Entwurf kann den Umzug nicht unterstützen. Du willst Unbeweglichkeit, du kannst keine Unterstützung haben. Die ersten Kommentare über die Unterstützung von move sagen mir, dass du * Unterstützung * verschieben willst; Ich behaupte einfach, dass du es nicht haben kannst. Das '= default' implementierte sie nicht; also habe ich explizit gesagt, dass es "= löschen" war. Ich habe dann die return-Anweisung geändert, um in-place zu erstellen, anstatt in den Rückgabewert zu wechseln. Dies hat gravierende Einschränkungen, wie ich vor der letzten Zeile beschrieben habe. Nach der letzten Zeile sage ich "nun, hier ist eine andere Lösung". – Yakk

Verwandte Themen