Jak mogę przekazać a std::unique_ptr
do funkcji? Powiedzmy, że mam następującą klasę:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
Następujące elementy nie są kompilowane:
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;
}
Dlaczego nie mogę przekazać a std::unique_ptr
do funkcji? Z pewnością to jest główny cel konstrukcji? Czy też komisja C ++ miała zamiar wrócić do surowych wskaźników w stylu C i przekazać to w ten sposób:
MyFunc(&(*ptr));
A co najdziwniejsze, dlaczego jest to dobry sposób na to, by go ominąć? Wydaje się okropnie niekonsekwentne:
MyFunc(unique_ptr<A>(new A(1234)));
c++
c++11
unique-ptr
user3690202
źródło
źródło
Odpowiedzi:
Zasadniczo są tutaj dwie opcje:
Przekaż inteligentny wskaźnik przez odniesienie
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); }
Przenieś inteligentny wskaźnik do argumentu funkcji
Zauważ, że w tym przypadku asercja zostanie zachowana!
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) }
źródło
unique_ptr
przez referencję tylko wtedy, gdy funkcja może lub nie może się z niej ruszyć. A potem powinno to być odniesienie do wartości r. Aby obserwować obiekt bez wymagania czegokolwiek na temat jego semantyki własności, użyj odniesienia takiego jakA const&
lubA&
.ptr
po przeprowadzce.Przekazujesz to według wartości, co oznacza wykonanie kopii. To nie byłoby wyjątkowe, prawda?
Możesz przenieść wartość, ale oznacza to przekazanie własności obiektu i kontrolę jego życia do funkcji.
Jeśli czas życia obiektu jest gwarantowany przez cały czas trwania wywołania MyFunc, po prostu przekaż nieprzetworzony wskaźnik via
ptr.get()
.źródło
Nie możesz tego zrobić, ponieważ
unique_ptr
ma konstruktor przenoszenia, ale nie ma konstruktora kopiującego. Zgodnie ze standardem, jeśli zdefiniowano konstruktor przenoszenia, ale nie zdefiniowano konstruktora kopiującego, konstruktor kopiujący jest usuwany.Możesz przekazać
unique_ptr
do funkcji przy pomocy:void MyFunc(std::unique_ptr<A>& arg) { cout << arg->GetVal() << endl; }
i używaj go tak, jak masz:
lub
void MyFunc(std::unique_ptr<A> arg) { cout << arg->GetVal() << endl; }
i używaj go jak:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234)); MyFunc(std::move(ptr));
Ważna uwaga
Zauważ, że jeśli używasz drugiej metody,
ptr
nie ma prawa własności do wskaźnika po wywołaniustd::move(ptr)
return.void MyFunc(std::unique_ptr<A>&& arg)
miałby taki sam efekt jakvoid MyFunc(std::unique_ptr<A>& arg)
ponieważ oba są odniesieniami.W pierwszym przypadku
ptr
nadal ma własność wskaźnika po wywołaniuMyFunc
.źródło
Ponieważ
MyFunc
nie przejmuje na własność, lepiej byłoby mieć:void MyFunc(const A* arg) { assert(arg != nullptr); // or throw ? cout << arg->GetVal() << endl; }
albo lepiej
void MyFunc(const A& arg) { cout << arg.GetVal() << endl; }
Jeśli naprawdę chcesz przejąć na własność, musisz przenieść swój zasób:
std::unique_ptr<A> ptr = std::make_unique<A>(1234); MyFunc(std::move(ptr));
lub przekaż bezpośrednio odniesienie do wartości r:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr
nie ma celowo kopii gwarantującej posiadanie tylko jednego właściciela.źródło
ptr.get()
czy tylko przekazujeszptr
do funkcji?MyFunc
dla przekazania odniesienia wartości r?void MyFunc(A&& arg)
bierze odniesienie do wartości r ...typedef int A[]
,MyFunc(std::make_unique<A>(N))
daje błąd kompilatora: błąd: niepoprawna inicjalizacja odniesienia typu „int (&&) []” z wyrażenia typu „std :: _ MakeUniq <int []> :: __ array” { aka 'std :: unique_ptr <int [], std :: default_delete <int []>>'} Czy jestg++ -std=gnu++11
wystarczająco aktualny?Możesz, ale nie przez kopiowanie - ponieważ
std::unique_ptr<>
nie można go kopiować.Między innymi
std::unique_ptr<>
ma na celu jednoznaczne oznaczenie unikalnej własności (w przeciwieństwie dostd::shared_ptr<>
).Ponieważ w tym przypadku nie ma konstrukcji kopiowania.
źródło
Ponieważ
unique_ptr
służy do unikalnej własności, jeśli chcesz przekazać to jako argument, spróbujAle po tym, że stan
ptr
INmain
będzienullptr
.źródło
unique_ptr
raczej bezużyteczne.Przekazywanie funkcji
std::unique_ptr<T>
jako wartość nie działa, ponieważ, jak wspomnieliście,unique_ptr
nie można jej skopiować.A co z tym?
std::unique_ptr<T> getSomething() { auto ptr = std::make_unique<T>(); return ptr; }
ten kod działa
źródło