2013-10-02 4 views
7

Ich implementiere eine Factory-Klasse, die einen Vektor von uint8_t erstellt. Ich möchte in der Lage sein, die Bewegungssemantik zu verwenden, wenn der resultierende Vektor zurückgegeben wird. Das scheint zu funktionieren, aber ich bin nicht zuversichtlich, dass dies der richtige Weg ist, um das zu erreichen, was ich will.Wie verwende ich die Bewegungssemantik beim Zurückgeben einer Elementvariablen?

Ich habe einige Beispiele gesehen, wie eine zurückgegebene automatische Variable als rvalue betrachtet wird und den Move-Konstruktor des aufrufenden Codes verwendet, aber in meinem Beispiel ist das zurückgegebene Objekt ein Member. Ich weiß, dass das Mitglied seinen Inhalt verliert, wenn der Aufrufer den Rückgabewert in einen Move-Konstruktor einfügt - und genau das möchte ich.

ich habe so etwas wie folgt geschrieben:

#include <cstdint> 
#include <iostream> 
#include <vector> 

class Factory 
{ 
public: 
    std::vector<uint8_t> _data; 

    Factory(std::size_t size) : 
     _data(size, 0) 
    { 
    } 

    void buildContent(int param) 
    { 
     // perform operations on the contents of _data 
    } 

    std::vector<uint8_t> && data() 
    { 
     return std::move(_data); 
    } 
}; 

int main() 
{ 
    Factory factory(42); 
    factory.buildContent(1); 
    std::vector<uint8_t> temp(factory.data()); 
    std::cout << "temp has " << temp.size() << " elements" << std::endl; 
    std::cout << "factory._data has " << factory._data.size() << " elements" << std::endl; 

    return 0; 
} 

Edit:

Oh, und den Beispielcode gibt die folgenden:

temp has 42 elements 
factory._data has 0 elements 
+1

Also, was ist Ihre Frage? – DanielKO

+0

"Ich bin nicht davon überzeugt, dass dies der richtige Weg ist, um das zu erreichen, was ich will." – Geoffroy

+0

Oh, ich sehe jetzt. Überprüfen Sie dieses eine: http://StackOverflow.com/Questions/9914548/using-of-Rvalue-References-in-C11 – DanielKO

Antwort

5

Zunächst einmal haben Sie um zu entscheiden, was du willst. Wollen Sie wirklich Daten aus Ihrer Instanz herausholen? Wenn ja, was Sie haben, erreicht das in Ordnung. Auf der anderen Seite sieht es ziemlich unsicher aus. Was Sie tun können, verwenden Referenz-Qualifikation zu erzwingen, dass Sie nur eine rvalue Referenz zurück, wenn die Instanz selbst ist eine rvalue Referenz:

std::vector<uint8_t> && data() && // called on rvalue 
{ 
    return std::move(_data); 
} 

// return lvalue ref or value 
std::vector<uint8_t>& data() & // called on lvalue 
{ 
    return _data; 
} 

Am Ende alles hängt davon ab, welches Problem Sie versuchen zu lösen, die ist nicht aus Ihrer Frage ersichtlich.

+0

Gibt es einen Compiler, der diese Syntax unterstützt? (&& nach der Methodendeklaration) –

+0

@ BЈовић [Anscheinend, GCC 4.8.1] (http://gcc.gnu.org/projects/cxx0x.html), obwohl ich es nicht getestet habe. – juanchopanza

1

Wenn Ihr Compiler Rvalue-Verweise darauf hat (&& nach Methoden), möchten Sie vielleicht das verwenden. Siehe @ Juanchopanzas Antwort.

Wenn Sie nicht, möchten Sie zuerst sicherstellen, dass data() macht klar, dass Sie sich bewegen. Es gibt ein paar Möglichkeiten, dies zu tun.

Zuerst können Methoden, die keine Mitglieder sind (friend s), auf && überschreiben. So können Sie diese Syntax erhalten:

std::vector<uint8_t> temp(get_data(std::move(factory)); 

wo get_data hat && und & Überlastungen auf Ihrem factory Typ und entweder bewegt oder nicht, basierend von ihm weg.

Als nächstes möchten Sie eine std::vector<uint8_t> anstelle einer `std::vector<uint8_t>&& für Lebensdauerverlängerungsprobleme zurückgeben. Die Laufzeitkosten liegen zwischen Null und Klein, aber die beseitigten Bugs sind lohnenswert.

Wenn create_factory ein Factory Objekt zurückgibt, dann, wenn wir dies tun:

for(uint8_t x : get_data(create_factory())) 

die get_data, die eine && kehrt nicht funktioniert, während die, die eine temporäre Arbeiten einwandfrei zurückgibt.

Was ist los? Nun, Entfernungsbasierte For-Schleifen sind so definiert, dass sie die Sache, die Sie durchlaufen, an eine Referenz binden. Eine temporäre Bindung an eine Referenz verlängert ihre Lebensdauer: Eine Referenz, die an eine Referenz gebunden ist, hat keine lebenslange Erweiterung. Die Lebensdauer der Rückgabewerte der Funktion create_factory wird in beiden Fällen nicht verlängert.

Mit dem && Fall, der Verweis auf Vektor bleibt hängen. Mit dem Rückgabe-temporären Fall wird der Vektor factory in das Temporäre verschoben, dann wird die Lebensdauer des Provisoriums verlängert.

Kurz gesagt, die Rückkehr && Referenzen ist sehr selten eine gute Idee.

0

Wie wäre es, den Zuweisungsoperator in Ihrem Vektor zu verstecken und nur den Zuweisungsoperator zu implementieren (das Kopieren im Wesentlichen zu unterlassen - wenn Sie das wollen).

Damit dies:

std::vector<uint8_t> temp(factory.data()); 

wird nicht kompiliert, wenn Sie es so weit ändern:

std::vector<uint8_t> temp(std::move(factory)); 
+0

Wie würde ich den Kopierkonstruktor oder den Zuweisungsoperator von std :: vector verstecken? – anorm

+0

Was ich sagen wollte, ist, wenn Sie die Bedeutung Ihrer Fabrik ändern, um eher wie eine Erweiterung zu einem Vektor zu handeln, entweder durch Vererben (IS-A-Vektor) oder Einwickeln (HAS-A-Vektor) würden Ihre Kunden dann mit einer Fabrik umgehen (die Sie umbenennen müssten, um die neue Bedeutung wiederzugeben). Alternativ könnten Sie einen nicht kopierbaren Vektor erstellen und ihn statt von std :: vector aus der Fabrik zurückgeben, was aber zu kompliziert klingt. Das Problem mit Ihrem Ansatz ist der Aufruf von facotry.data() wird diese Daten ungültig machen, die verwirrend sein könnten. – Sereger

Verwandte Themen