524 Stimmen

C++11 rvalues und move-Semantik Verwirrung (return-Anweisung)

Ich versuche, rvalue-Referenzen und die Move-Semantik von C++11 zu verstehen.

Was ist der Unterschied zwischen diesen Beispielen, und wer von ihnen wird keine Vektorkopie erstellen?

Erstes Beispiel

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return tmp;
}

std::vector<int> &&rval_ref = return_vector();

Zweites Beispiel

std::vector<int>&& return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();

Drittes Beispiel

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();

2voto

Andrej Podzimek Punkte 1702

Wie bereits in den Kommentaren zur ersten Antwort erwähnt, ist die return std::move(...); Konstrukt kann in anderen Fällen als der Rückgabe von lokalen Variablen einen Unterschied machen. Hier ist ein runnable Beispiel, das dokumentiert, was passiert, wenn Sie ein Mitgliedsobjekt mit und ohne std::move() :

#include <iostream>
#include <utility>

struct A {
  A() = default;
  A(const A&) { std::cout << "A copied\n"; }
  A(A&&) { std::cout << "A moved\n"; }
};

class B {
  A a;
 public:
  operator A() const & { std::cout << "B C-value: "; return a; }
  operator A() & { std::cout << "B L-value: "; return a; }
  operator A() && { std::cout << "B R-value: "; return a; }
};

class C {
  A a;
 public:
  operator A() const & { std::cout << "C C-value: "; return std::move(a); }
  operator A() & { std::cout << "C L-value: "; return std::move(a); }
  operator A() && { std::cout << "C R-value: "; return std::move(a); }
};

int main() {
  // Non-constant L-values
  B b;
  C c;
  A{b};    // B L-value: A copied
  A{c};    // C L-value: A moved

  // R-values
  A{B{}};  // B R-value: A copied
  A{C{}};  // C R-value: A moved

  // Constant L-values
  const B bc;
  const C cc;
  A{bc};   // B C-value: A copied
  A{cc};   // C C-value: A copied

  return 0;
}

Vermutlich, return std::move(some_member); ist nur dann sinnvoll, wenn Sie das betreffende Klassenmitglied tatsächlich verschieben wollen, z. B. in einem Fall, in dem class C repräsentiert kurzlebige Adapterobjekte mit dem einzigen Zweck, Instanzen von struct A .

Beachten Sie, wie struct A bekommt immer kopiert aus class B auch wenn die class B Objekt ist ein R-Wert. Das liegt daran, dass der Compiler keine Möglichkeit hat, zu erkennen, dass class B Instanz von struct A nicht mehr verwendet werden. Unter class C verfügt der Compiler über diese Informationen aus std::move() Deshalb struct A erhält umgezogen , es sei denn, die Instanz von class C konstant ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X