2013-02-25 5 views
7

std wurde diese move'ed:erhalte eine Fehlermeldung, oder zumindest eine Warnung, wenn eine Variable, die :: anderswo

void foo(int &&r) { 
    std::cout << r << std::endl; 
} 

int main() { 
    int i = 2; 
    foo(std::move(i)); 
    i = 3; //no warning. any way to get some warnings here? 
    return 0; 
} 

Gibt es keine Möglichkeit, den Compiler sagen Sie mir, einen Fehler zu geben (oder Warnung) wenn ich die Variable versehentlich benutze, nachdem ich sie verschoben habe? Ich denke, das wäre sehr praktisch. Viele Male finde ich mich bewegende Variablen anderswo, aber dann muss ich manuell SEHR VORSICHTIG sein, dass ich sie danach nicht benutze. Nun, das hat noch keine Probleme verursacht, aber wer weiß das schon ... besser sicher!

Vielleicht gibt es einige Preprozessor-Tricks (oder ziemlich weit verbreitete Compiler-Erweiterungen), die es gibt, um das Zeug zu machen?


realistischeres Beispiel:

struct HugeStorage { 
    std::vector<double> m_vec; 
    HugeStorage(std::vector<double> vec) : m_vec(std::move(vec)) { } 
}; 

struct SmallStorage { 
    std::vector<double> m_vec; 
    SmallStorage(std::vector<double> vec) : m_vec(std::move(vec)) { } 
}; 

std::vector<double> vec_from_data_source() { 
    return std::vector<double>(); //only example!! 
} 

int main() { 
    std::vector<double> vec = vec_from_data_source(); 
    if (vec.size() > 10000) 
    { 
    HugeStorage storage(std::move(vec)); 
    //do some things, but I gotta be careful I don't do anything to vec 
    } 
    else 
    { 
    SmallStorage storage(std::move(vec)); 
    //do some things, but I gotta be careful I don't do anything to vec 
    } 
    return 0; 
} 
+2

Die Variable wurde nicht verschoben, nur ihr Wert. Es ist absolut nichts falsch daran, ihm einen neuen Wert zuzuweisen. –

+0

Welche "Probleme" sehen Sie voraus und was ist das * tatsächliche * Problem mit dem Code, den Sie zeigen? –

+0

@NikBougalis Aktualisiert mit realistischerem Beispiel – user2015453

Antwort

10

Gibt es keine Möglichkeit, den Compiler sagen Sie mir einen Fehler (oder Warnung) zu geben, wenn ich versehentlich die Variable verwenden, nachdem ich es bewegt haben?

Die Antwort ist „Nein, es gibt keinen Weg“ (nach bestem Wissen und Gewissen zumindest keine derzeit verfügbaren Compiler bietet eine solche Option, und das aus gutem Grund - siehe unten).

Auch wenn das überhaupt möglich war, warum sollten Sie in diesem Fall eine Warnung oder noch schlimmer einen Fehler erwarten? Zuallererst unterscheidet sich das Verschieben von einer Ganzzahl nicht von dem Kopieren.

Zweitens, für meisten Typen, ist die Zuweisung eines verschobenen Objekts dieses Typs eine vollkommen legale Operation; Dies gilt immer für grundlegende Typen wie int, und es gilt definitiv für std::vector, obwohl es möglicherweise nicht für andere Typen gilt.

Im Allgemeinen hängt die Zuordnung eines verschobenen Objekts von den jeweiligen Nachbedingungen des Verschiebevorgangs für diesen Typ und den Vorbedingungen des Zuweisungsoperators ab (der Zuweisungsoperator für Typen der Standardbibliothek) haben auf dem linken Argument keine Vorbedingungen). Dies kann ein Compiler im allgemeinen Fall nicht überprüfen.

Deshalb, wenn Sie sind auf:

  1. Verschieben von einem Objekt, für das die Bewegung Zuordnung oder Konstruktor der eingefahrenen von Objekt in einem nicht näher bezeichnet Zustand (das ist der Fall für std::vector) bewegt platziert und dann;
  2. Invoke jede Funktion mit Voraussetzungen über den Zustand des Objekts (und das ist nicht der Fall für die Zuordnung zu einem std::vector);

Das wäre sicherlich schlecht.Auf der anderen Seite, wird der Compiler eine Möglichkeit haben, keine semantische Analyse Ihres Programms und finden Sie heraus, ob dies der Fall ist auszuführen:

A x, y; 
... 
if (complicatedCondition()) 
{ 
    y = move(x); 
} 

foo(x); // Did I move from x? And if so, is it safe to call foo()? 

Außerdem nicht vergessen, dass die Philosophie von C++ ist um dir Kraft und (meistens) Designrichtlinien zu geben, aber "lässt dich deine Füße schießen", wenn du wirklich versuchst, das zu tun.

Es sind gefährlich, sogar sinnlose Dinge, die Sie in C tun können, ++ (wird der Compiler gibt Ihnen eine Warnung oder einen Fehler, wenn Sie auf delete den gleichen Zeiger zweimal versuchen?), Aber die Sprache selbst gewonnen‘ t verhindern, dass Sie sie tun, unter der Annahme, dass Sie wirklich, wirklich wissen, was Sie tun.

+0

Bei Bibliothekstypen gibt es keine Garantie, dass das Objekt * zuweisbar * ist, nur dass es * zerstörbar * ist. Allerdings bieten viele Bibliotheksimplementierungen zusätzliche Garantien, was der Standard erfordert. –

+6

@ DavidRodríguez-dribeas: 17.6.5.15/p1 garantiert, dass alle von std :: lib verschobenen Typen in einem gültigen, aber nicht spezifizierten Zustand sind. Das bedeutet, dass, wenn der Typ keine Vorbedingung für die lhs einer Zuweisungsanweisung hat, dieser zugeordnet werden kann, selbst wenn er von ihm entfernt wurde. Beachten Sie, dass diese allgemeine Anweisung auf Typen in der std-lib und nicht auf Typen im Allgemeinen angewendet wird. Und mir ist kein std :: type bekannt, dem eine Vorbedingung zugewiesen werden muss. –

+1

@HowardHinnant: Danke für die Klärung. –

0

Ich glaube, Sie versuchen, Schritt als Ersatz der variablen Umfang nutzen zu können.

int main() 
{ 
    { 
    int i = 2; 
    foo(std::move(i)); 
    } 
    i = 3; // error! 
    return 0; 
} 
+0

Nun, das funktioniert in den einfachsten Fällen, aber es ist etwas ... – user2015453

+0

Ich denke, Sie verwenden Move Semantik falschen Weg, eine Art Ersatz des Umfangs, meine Antwort zeigt, dass, mehr reale Beispiel, dann können wir schauen. – Slava

5
//do some things, but I gotta be careful I don't do anything to vec 

Klarstellung: Sie müssen vorsichtig sein, dass Sie nicht alles tun, um vec, die eine Voraussetzung erfordert. Sie kann alles mit vec tun, die nicht erfordert alle Vorbedingungen. Zum Beispiel können Sie vec einen neuen Wert zuweisen. Sie können vec.clear() anrufen. Sie können vec.size() anrufen. Aber rufen Sie nicht vec.pop_back(), weil diese Elementfunktion eine Vorbedingung hat.

+2

Falls es nicht für jeden offensichtlich ist, würde ich klarstellen, dass Sie nichts tun können, was eine Vorbedingung erfordert, ohne diese Voraussetzung zuerst zu überprüfen. Es ist in Ordnung, 'if (! Vec.empty()) vec.pop_back();' aufzurufen, weil Sie nach dem Aufruf von 'vec.empty()' wissen, dass die Voraussetzung erfüllt ist. –

+1

Ja, besser gesagt, danke Jonathan. –

Verwandte Themen