Bagaimana cara mengirimkan a std::unique_ptr
ke suatu fungsi? Katakanlah saya memiliki kelas berikut:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
Berikut ini tidak dapat dikompilasi:
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;
}
Mengapa saya tidak dapat meneruskan a std::unique_ptr
ke suatu fungsi? Tentunya ini tujuan utama dari konstruksinya? Atau apakah komite C ++ bermaksud agar saya kembali ke petunjuk gaya C mentah dan meneruskannya seperti ini:
MyFunc(&(*ptr));
Dan yang paling aneh dari semuanya, mengapa ini cara yang OK untuk melewatinya? Tampaknya sangat tidak konsisten:
MyFunc(unique_ptr<A>(new A(1234)));
c++
c++11
unique-ptr
pengguna3690202
sumber
sumber
Jawaban:
Pada dasarnya ada dua opsi di sini:
Meneruskan penunjuk cerdas dengan referensi
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); }
Pindahkan penunjuk cerdas ke dalam argumen fungsi
Perhatikan bahwa dalam kasus ini, pernyataan akan berlaku!
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) }
sumber
unique_ptr
by reference jika fungsinya mungkin atau mungkin tidak berpindah darinya. Dan kemudian itu harus menjadi referensi nilai r. Untuk mengamati suatu objek tanpa memerlukan apa pun tentang semantik kepemilikannya, gunakan referensi sepertiA const&
atauA&
.ptr
setelah pindah.Anda meneruskannya dengan nilai, yang berarti membuat salinan. Itu tidak terlalu unik, bukan?
Anda bisa memindahkan nilainya, tetapi itu berarti meneruskan kepemilikan objek dan kontrol masa pakainya ke fungsi.
Jika masa pakai objek dijamin ada selama masa panggilan ke MyFunc, teruskan saja pointer mentah melalui
ptr.get()
.sumber
Anda tidak dapat melakukannya karena
unique_ptr
memiliki konstruktor pemindahan tetapi bukan konstruktor salinan. Menurut standar, ketika konstruktor pemindahan ditentukan tetapi konstruktor salinan tidak ditentukan, konstruktor salinan dihapus.Anda dapat meneruskan
unique_ptr
ke fungsi dengan menggunakan:void MyFunc(std::unique_ptr<A>& arg) { cout << arg->GetVal() << endl; }
dan gunakan seperti yang Anda miliki:
atau
void MyFunc(std::unique_ptr<A> arg) { cout << arg->GetVal() << endl; }
dan gunakan seperti:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234)); MyFunc(std::move(ptr));
Catatan penting
Harap dicatat bahwa jika Anda menggunakan metode kedua,
ptr
tidak memiliki kepemilikan pointer setelah panggilan untukstd::move(ptr)
kembali.void MyFunc(std::unique_ptr<A>&& arg)
akan memiliki efek yang samavoid MyFunc(std::unique_ptr<A>& arg)
karena keduanya adalah referensi.Dalam kasus pertama,
ptr
masih memiliki kepemilikan penunjuk setelah panggilan keMyFunc
.sumber
Karena
MyFunc
tidak mengambil kepemilikan, akan lebih baik untuk memiliki:void MyFunc(const A* arg) { assert(arg != nullptr); // or throw ? cout << arg->GetVal() << endl; }
atau lebih baik
void MyFunc(const A& arg) { cout << arg.GetVal() << endl; }
Jika Anda benar-benar ingin mengambil alih kepemilikan, Anda harus memindahkan sumber daya Anda:
std::unique_ptr<A> ptr = std::make_unique<A>(1234); MyFunc(std::move(ptr));
atau berikan referensi nilai-r secara langsung:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr
tidak memiliki salinan dengan tujuan untuk menjamin hanya memiliki satu pemilik.sumber
ptr.get()
atau hanya meneruskanptr
ke fungsi?MyFunc
untuk meneruskan referensi nilai-r?void MyFunc(A&& arg)
mengambil referensi nilai-r ...typedef int A[]
,MyFunc(std::make_unique<A>(N))
memberikan kesalahan kompiler: error: inisialisasi referensi yang tidak valid dari tipe 'int (&&) []' dari ekspresi tipe 'std :: _ MakeUniq <int []> :: __ array' { aka 'std :: unique_ptr <int [], std :: default_delete <int []>>'} Apakahg++ -std=gnu++11
cukup terkini?Anda bisa, tetapi tidak dengan menyalin - karena
std::unique_ptr<>
tidak dapat dibuat salinan.Antara lain,
std::unique_ptr<>
dirancang untuk secara tegas menandai kepemilikan unik (sebagai lawanstd::shared_ptr<>
).Karena dalam kasus itu, tidak ada konstruksi salinan.
sumber
Karena
unique_ptr
untuk kepemilikan unik, jika Anda ingin menyebarkannya sebagai argumen cobaTetapi setelah itu keadaan
ptr
dalammain
akan menjadinullptr
.sumber
unique_ptr
akan menjadi tidak berguna.Meneruskan
std::unique_ptr<T>
sebagai nilai ke suatu fungsi tidak berfungsi karena, seperti yang Anda sebutkan,unique_ptr
tidak dapat disalin.Bagaimana dengan ini?
std::unique_ptr<T> getSomething() { auto ptr = std::make_unique<T>(); return ptr; }
kode ini berfungsi
sumber