return static variable via move



  • Hallo

    class MySingleClassInstance
    {
        static MySingleClassInstance&& GetInstance()
        {
            static MySingleClassInstanceinstance;
            return std::move(instance);
        }
    
        MySingleClassInstance(const MySingleClassInstance& other) = delete;
        MySingleClassInstance(MySingleClassInstance&& other) noexcept = default;
        MySingleClassInstance& operator=(const MySingleClassInstance& other) = delete;
        MySingleClassInstance& operator=(MySingleClassInstance&& other) noexcept = default;
    
    }
    
    main()
    {
       auto instance = MySingleClassInstance::GetInstance();
    }
    

    wieso erhalte ich hier den Fehler

    'MySingleClassInstance::MySingleClassInstance(const MySingleClassInstance&)': attempting to reference a deleted function.
    

    Ich rufe hier doch die Move Funktionalität auf und nicht den Kopierkonstruktor.



  • Den gezeigten Code hast du nicht übersetzt.



  • Dein Code passt nicht zur Fehlermeldung.

    Alles public, Default-Ctor und ein Leerzeichen beim Erzeugen der Variable, funktioniert dann:

    Code



  • Ich hoffe doch, das war nur ein Experiment und du erwägst nicht ernsthaft, GetInstance eine rvalue-Referenz zurückgeben zu lassen.



  • Es ist ein Experiment. Wollte wissen was passiert wenn ich eine static variable weg 'move'.

    Die Fehler im Code kommen davon dass ich diesen nicht kopiert habe sondern nochmals mit erfundenem Namen neu geschreiben habe.

    Ich kopier mal den original Code

    class CommunicationManager
    {
        CommunicationManager() = default;
    
    public:
    
        static CommunicationManager&& GetInstance()
        {
            static CommunicationManager instance;
            return std::move(instance);
        }
    
        ~CommunicationManager() = default;
    
        CommunicationManager(const CommunicationManager& other) = delete;
        CommunicationManager(CommunicationManager&& other) noexcept = default;
        CommunicationManager& operator=(const CommunicationManager& other) = delete;
        CommunicationManager& operator=(CommunicationManager&& other) noexcept = default;
    }
    
    auto instance = CommunicationManager::GetInstance();
    
    'CommunicationManager::CommunicationManager(const CommunicationManager &)': attempting to reference a deleted function
    


  • optimizer schrieb:

    Die Fehler im Code kommen davon dass ich diesen nicht kopiert habe sondern nochmals mit erfundenem Namen neu geschreiben habe.

    Tja, wenn es dir nicht der Mühe wert ist, dann mir auch nicht. Auch der neue Code ist nicht übersetzbar (unabhängig von deinem Fehler).



  • Tja, wenn es dir nicht der Mühe wert ist, dann mir auch nicht.

    Was meinst du damit.

    Ich meinte ich habe meinen Original Code hier nochmals neu getippt habe mit anderen Namen. Dabei habe ich dann das public vergessen und bei
    static MySingleClassInstanceinstance kein Leerzeichen gelassen.

    Ist es jetzt strafbar wenn man nen Fehler macht?

    Auch der neue Code ist nicht übersetzbar (unabhängig von deinem Fehler).

    ??



  • 'CommunicationManager::CommunicationManager(const CommunicationManager &)': attempting to reference a deleted function
    

    Er versucht offensichtlich trotzdem zu kopieren, was nicht geht.

    Wenn ich den Code bei mir mit g++ 7.3 übersetze, übersetzt er das so 1 zu 1 tatsächlich, er ruft den Move Konstruktor auf und wenn ich dann versuche die Member auszugeben bleibt nur Schrott über. Selbst schon beim ersten Aufruf von GetInstance, nicht erst beim Zweiten.

    auto&& instance = CM::GetInstance();
    

    Hier wird kein Move Konstruktor mehr aufgerufen und ich zerstöre mir nicht mehr die Innereien.

    struct Test
    {
        Test() {std::cout << "created T\n";}
    
        Test(const Test& other) {std::cout << "copied T\n";}
        Test(Test&& other) noexcept {std::cout << "moved T\n";}
        Test& operator=(const Test& other) {std::cout << "copied2 T\n";}
        Test& operator=(Test&& other) noexcept  {std::cout << "moved2 T\n";}
    
    };
    
    class CommunicationManager
    {
        Test t;
        int bla; // 1 in Konstruktor zugewiesen, nicht hier.
        /* ... */
    };
    
    int main()
    {
        auto i1 = CommunicationManager::GetInstance();
        std::cout << i1.bla << "\n"; // -> schrott
        auto i2 = CommunicationManager::GetInstance();
        std::cout << i2.bla << "\n"; // -> schrott
    }
    

    created T
    created T
    moved CommunicationManager
    created T
    moved CommunicationManager



  • optimizer schrieb:

    Ist es jetzt strafbar wenn man nen Fehler macht?

    Wurdest du bestraft?



  • Hier wird kein Move Konstruktor mehr aufgerufen und ich zerstöre mir nicht mehr die Innereien.

    Wie gesagt das hat natürlich keinen Sinn gemacht eine static Variable zu moven.

    Aber das verstehe ich nun nicht:

    auto&& instance = CM::GetInstance();
    

    Was passiert dann da. instance ist dann eine rvalue referenz?



  • optimizer schrieb:

    Tja, wenn es dir nicht der Mühe wert ist, dann mir auch nicht.

    Was meinst du damit.

    Ich meinte ich habe meinen Original Code hier nochmals neu getippt habe mit anderen Namen.

    Auch dein neuer Code compiliert (nachdem man Dinge tut wie ein Semikolon ans Ende zu setzen und <utility> für std::move einzubinden) und reproduziert eben nicht deinen Fehler.

    Daher ist es irgendwie sinnlos, über die Ursache deiner Fehlermeldung zu diskutieren, da du Code zeigst, der nicht dazu passt.

    (ach ja, mach das Code-Beispiel vollständing (aber minimal), also mit #includes, sodass man es schnell kompilieren kann)



  • optimizer schrieb:

    Aber das verstehe ich nun nicht:

    auto&& instance = CM::GetInstance();
    

    Was passiert dann da. instance ist dann eine rvalue referenz?

    Wichtig: auto&& ist etwas anderes als KonkreterTyp&& ! Es wird nämlich automatisch zu einer L- oder R-Value-Referenz, je nach dem, womit initialisiert wird.



  • Auch dein neuer Code compiliert (nachdem man Dinge tut wie ein Semikolon ans Ende zu setzen und <utility> für std::move einzubinden) und reproduziert eben nicht deinen Fehler.

    Tut er nicht. Zumindest nicht unter visual studio 2017

    Wichtig: auto&& ist etwas anderes als KonkreterTyp&&! Es wird nämlich automatisch zu einer L- oder R-Value-Referenz, je nach dem, womit initialisiert wird.

    Ja ok das habe ich inzwischen nachgelesen.

    Aber dass ich eine static variable move sollte ja eigentlich per definition nicht funktionieren. Oder?



  • Ich frage mich das auch und habe auch noch etwas weiter experimentiert.

    struct Test
    {
        int a;
        Test() : a{2} {std::cout << "created\n";}
    
        Test& operator=(Test const&) = delete;
        Test& operator=(Test&&) = default;
        Test(Test const&) = delete;
        Test(Test&&) = default;
    };
    
    Test&& foo()
    {
        static Test t;
        return std::move(t);
    }
    
    int main()
    {
        auto t = foo();
        std::cout << t.a << "\n";
        auto t2 = foo();
        std::cout << t2.a << "\n";
    }
    

    Ausgabe:

    2
    2

    Das gleiche, aber in Zeile 9

    Test(Test&&) {};
    

    Ausgabe (vermutlich undefiniert):

    0
    8

    Getestet mit clang und g++. Gleiches/Ähnliches Verhalten.
    Kann das jemand erklären?



  • 1. Warum sollte das moven von einer static-Variablen nicht funktionieren?
    Natürlich tut es das. Nur ist die Variable nach dem ersten move eben in einem moved-from-State. Was das bedeutet, hängt eben vom Typ an. Niemand hindert dich daran, dass dein Typ auch nach einem move noch brauchbar ist. STL-Typen sind danach "valid but unspecified".

    2. Deine Testklasse enthält einen int. copy und move sind für int identisch (was sollte da bei move auch anders sein?!). Das move wird also als copy implementiert sein. Daher bekommst du eben beide Male den korrekten Wert. Und wenn dein move gar nichts tut, dann kommt auch nix sinnvolles raus.



  • ups.

    nvm, ich verzieh mich mal in eine dunkle Ecke.


Anmelden zum Antworten