std::vector und move-semantics

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

std::vector und move-semantics

Beitrag von eXile »

Wieder einmal ein wohl semi-triviales Problem von mir.

Ich habe gerade folgendes Problem: Ich habe Objekte vom Typ MyClass, welche
  1. Nicht default-konstruierbar sind,
  2. nicht kopier-konstruierbar sind,
  3. nicht kopier-zuweisbar sind.
Ich habe nun zwei std::vector<MyClass> namens v1 und v2. In v1 sind ein paar Objekte enthalten. Manche von denen will ich nach v2 bewegen.

Code (auch wie immer in Farbe):

Code: Alles auswählen

#include <iostream>
#include <cassert>
#include <vector>

class MyClass
{
public:
    explicit MyClass(
        int theA, 
        int theB
    ) : myA(theA), 
        myB(theB)
    {
        return;
    };
    
    MyClass(
        MyClass && theOther
    ) : myA(std::move(theOther.myA)), 
        myB(std::move(theOther.myB))
    {
        return;
    }
    
    MyClass & operator=(
        MyClass && theOther
    ) {
        assert(this != &theOther);
        
        myA = std::move(theOther.myA);
        myB = std::move(theOther.myB);
    }
    
private:
    // Not default-constructible. 
    explicit MyClass();

    // Enforce move-semantics. 
    MyClass(const MyClass & theOther);
    MyClass & operator=(const MyClass & theOther);

public:
    int myA;
    int myB;
};

int main(int argc, char * argv[])
{
    std::vector<MyClass> v1;
    std::vector<MyClass> v2;
    
    v1.push_back(MyClass(1, 2));
    v1.push_back(MyClass(2, 3));
    v1.push_back(MyClass(2, 4));
    
    // Works.
    for(auto i = 0u; i < v1.size(); i++)
        if(v1[i].myA == 2)
            v2.push_back(std::move(v1[i]));

/*
    // Does not work: Calls copy-constructor.
    for(auto i = v1.cbegin(); i != v1.cend(); i++)
        if(i->myA == 2)
            v2.push_back(std::move(*i));
*/

    // list1 may not be used any longer!
    
    return 0;
}
Wie man sieht, funktioniert das nicht mit Iteratoren; die würde ich jedoch ganz gerne verwenden (Vergleich mit einem std::find-Resultat). Alles, was ich im Internet sonst dazu gefunden habe, läuft auf std::swap hinaus, was ich (so weit ich das sehe) hier nicht benutzen kann, weil das Objekt nicht default-konstruierbar ist.

Das sieht doch schon wieder nach einem solchen Standard-Problem aus, als dass es in jedem C++-Buch stehen müsste; ich finde aber händeringend absolut nichts dazu. :|
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: std::vector und move-semantics

Beitrag von CodingCat »

Das einzige Problem, das ich sehe, ist, dass deine Iteratoren (fälschlicherweise?) const sind. Da dein Move-Konstruktor mit non-const R-Val-References arbeitet (was in der Regel sinnvoll ist, weil die Quellobjekte i.d.R. tatsächlich verändert werden), tut der Compiler das einzig Richtige und ruft den Kopier-Konstruktor auf.

Ansonsten funktioniert das einwandfrei: http://ideone.com/afiMHs (Änderung: begin & end statt cbegin & cend)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: std::vector und move-semantics

Beitrag von eXile »

CodingCat hat geschrieben:Das einzige Problem, das ich sehe, ist, dass deine Iteratoren (fälschlicherweise?) const sind.
Exakt das war's. Ich war schon so sehr im cbegin- und cend-Trott drin, dass ich das nicht mehr bemerkt habe. Vielen Dank.
Antworten