Wie kann ich ein std::unique_ptr
in eine Funktion übergeben? Nehmen wir an, ich habe folgende Klasse:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
Folgendes wird nicht kompiliert:
void MyFunc(unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(ptr);
return 0;
}
Warum kann ich a nicht an std::unique_ptr
eine Funktion übergeben? Dies ist sicherlich der Hauptzweck des Konstrukts? Oder wollte das C ++ - Komitee, dass ich auf rohe C-Zeiger zurückgreife und es so weitergebe:
MyFunc(&(*ptr));
Und am seltsamsten ist, warum ist dies eine gute Möglichkeit, es weiterzugeben? Es scheint schrecklich inkonsistent:
MyFunc(unique_ptr<A>(new A(1234)));
c++
c++11
unique-ptr
user3690202
quelle
quelle
Antworten:
Grundsätzlich gibt es hier zwei Möglichkeiten:
Übergeben Sie den Smart Pointer als Referenz
void MyFunc(unique_ptr<A> & arg) { cout << arg->GetVal() << endl; } int main(int argc, char* argv[]) { unique_ptr<A> ptr = unique_ptr<A>(new A(1234)); MyFunc(ptr); }
Bewegen Sie den Smart Pointer in das Funktionsargument
Beachten Sie, dass in diesem Fall die Behauptung gilt!
void MyFunc(unique_ptr<A> arg) { cout << arg->GetVal() << endl; } int main(int argc, char* argv[]) { unique_ptr<A> ptr = unique_ptr<A>(new A(1234)); MyFunc(move(ptr)); assert(ptr == nullptr) }
quelle
unique_ptr
Referenz nur übergeben, wenn sich die Funktion möglicherweise von ihr entfernt oder nicht. Und dann sollte es eine Wertreferenz sein. Verwenden Sie eine Referenz wieA const&
oder, um ein Objekt zu beobachten, ohne dass etwas über seine Besitzersemantik erforderlich istA&
.ptr
nach dem Umzug ist.Sie übergeben es als Wert, was bedeutet, dass Sie eine Kopie erstellen. Das wäre doch nicht sehr einzigartig, oder?
Sie können den Wert verschieben, dies bedeutet jedoch, dass das Eigentum an dem Objekt und die Kontrolle über seine Lebensdauer an die Funktion übergeben werden.
Wenn die Lebensdauer des Objekts während der gesamten Lebensdauer des Aufrufs von MyFunc garantiert ist, übergeben Sie einfach einen Rohzeiger über
ptr.get()
.quelle
Sie können dies nicht tun, da
unique_ptr
es einen Verschiebungskonstruktor, aber keinen Kopierkonstruktor gibt. Gemäß dem Standard wird der Kopierkonstruktor gelöscht, wenn ein Verschiebungskonstruktor definiert ist, ein Kopierkonstruktor jedoch nicht definiert ist.Sie können das
unique_ptr
an die Funktion übergeben, indem Sie Folgendes verwenden:void MyFunc(std::unique_ptr<A>& arg) { cout << arg->GetVal() << endl; }
und benutze es wie du:
oder
void MyFunc(std::unique_ptr<A> arg) { cout << arg->GetVal() << endl; }
und benutze es wie:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234)); MyFunc(std::move(ptr));
Wichtige Notiz
Beachten Sie, dass bei Verwendung der zweiten Methode
ptr
der Zeiger nach dem Aufruf vonstd::move(ptr)
return nicht im Besitz des Zeigers ist .void MyFunc(std::unique_ptr<A>&& arg)
hätte den gleichen Effekt wievoid MyFunc(std::unique_ptr<A>& arg)
da beide Referenzen sind.Im ersten Fall
ptr
hat der Zeiger nach dem Aufruf von noch BesitzMyFunc
.quelle
Da
MyFunc
es kein Eigentum übernimmt, wäre es besser, Folgendes zu haben:void MyFunc(const A* arg) { assert(arg != nullptr); // or throw ? cout << arg->GetVal() << endl; }
oder besser
void MyFunc(const A& arg) { cout << arg.GetVal() << endl; }
Wenn Sie wirklich Eigentümer werden möchten, müssen Sie Ihre Ressource verschieben:
std::unique_ptr<A> ptr = std::make_unique<A>(1234); MyFunc(std::move(ptr));
oder übergeben Sie direkt eine r-Wert-Referenz:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr
hat nicht absichtlich eine Kopie, um zu garantieren, nur einen Besitzer zu haben.quelle
ptr.get()
oder nur übergebenptr
?MyFunc
für die Übergabe einer R-Wert-Referenz?void MyFunc(A&& arg)
nimmt R-Wert Referenz ...typedef int A[]
,MyFunc(std::make_unique<A>(N))
gibt der Compiler Fehler: Fehler: Ungültige Initialisierung der Referenz vom Typ 'int (&&) []' aus dem Ausdruck vom Typ 'std :: _ MakeUniq <int []> :: __ array' { aka 'std :: unique_ptr <int [], std :: default_delete <int [] >>'} Istg++ -std=gnu++11
neu genug?Sie können, aber nicht durch Kopieren - weil
std::unique_ptr<>
nicht kopierkonstruierbar ist.Unter anderem
std::unique_ptr<>
wird entwickelt , um eindeutig markieren einzigartiges Eigentum (im Gegensatz zustd::shared_ptr<>
).Denn in diesem Fall gibt es keine Kopierkonstruktion.
quelle
Da
unique_ptr
es sich um ein eindeutiges Eigentum handelt, versuchen Sie es, wenn Sie es als Argument übergeben möchtenAber danach wird der Zustand von
ptr
inmain
seinnullptr
.quelle
unique_ptr
wäre eher nutzlos.Die Übergabe
std::unique_ptr<T>
als Wert an eine Funktion funktioniert nicht, da sie, wie Sie bereits erwähnt haben,unique_ptr
nicht kopierbar ist.Was ist damit?
std::unique_ptr<T> getSomething() { auto ptr = std::make_unique<T>(); return ptr; }
Dieser Code funktioniert
quelle