Std :: unique_ptr nasıl bildirilir ve ne işe yarar?


95

Nasıl çalıştığını anlamaya std::unique_ptrçalışıyorum ve bunun için bu belgeyi buldum . Yazar şu örnekten başlıyor:

#include <utility>  //declarations of unique_ptr
using std::unique_ptr;
// default construction
unique_ptr<int> up; //creates an empty object
// initialize with an argument
unique_ptr<int> uptr (new int(3));
double *pd= new double;
unique_ptr<double> uptr2 (pd);
// overloaded * and ->
*uptr2 = 23.5;
unique_ptr<std::string> ups (new std::string("hello"));
int len=ups->size();

Kafamı karıştıran bu satırda

unique_ptr<int> uptr (new int(3));

Tamsayıyı argüman olarak kullanıyoruz (yuvarlak parantezler arasında) ve burada

unique_ptr<double> uptr2 (pd);

argüman olarak bir gösterici kullandık. hiç fark yapar mı?

Benim için de net olmayan, bu şekilde ifade edilen işaretçilerin, "normal" bir şekilde açıklanan işaretçilerden nasıl farklı olacağıdır.


13
new int(3)inttıpkı pdyeniye bir gösterici gibi yeniye bir işaretçi döndürür double.
David Schwartz

Yanıtlar:


89

Yapıcısı unique_ptr<T>tip bir nesnenin bir ham bir işaretçi kabul T(böylece, bir kabul T*).

İlk örnekte:

unique_ptr<int> uptr (new int(3));

İşaretçi, bir newifadenin sonucudur , ikinci örnekte ise:

unique_ptr<double> uptr2 (pd);

İşaretçi pddeğişkende saklanır .

Kavramsal olarak, hiçbir şey değişmez ( unique_ptrham bir işaretçiden bir a oluşturuyorsunuz), ancak ikinci yaklaşım potansiyel olarak daha tehlikelidir, çünkü örneğin şunları yapmanıza izin verir:

unique_ptr<double> uptr2 (pd);
// ...
unique_ptr<double> uptr3 (pd);

Böylece , aynı nesneyi etkili bir şekilde kapsayan (böylece benzersiz bir göstericinin anlamını ihlal eden) iki benzersiz işaretçiye sahip olmak .

Bu nedenle, benzersiz bir işaretçi oluşturmanın ilk biçimi mümkün olduğunda daha iyidir. Dikkat edin, C ++ 14'te şunları yapabileceğiz:

unique_ptr<int> p = make_unique<int>(42);

Hangisi daha net ve daha güvenli. Şimdi bu şüphenizle ilgili olarak:

Benim için de net olmayan, bu şekilde ifade edilen işaretçilerin, "normal" bir şekilde açıklanan işaretçilerden nasıl farklı olacağıdır.

Akıllı işaretçilerin nesne sahipliğini modellemesi ve o nesneye son (akıllı, sahip olma) işaretçi kapsam dışına çıktığında otomatik olarak sivri uçlu nesneyi yok etmeye özen göstermesi gerekiyor.

Bu şekilde delete, dinamik olarak tahsis edilen nesneler üzerinde yapmayı hatırlamanıza gerek kalmaz - akıllı işaretçinin yıkıcısı bunu sizin için yapar - ya da zaten yok edilmiş bir nesneye (sarkan) bir işaretçiye başvurmayacağınız konusunda endişelenmenize gerek kalmaz:

{
    unique_ptr<int> p = make_unique<int>(42);
    // Going out of scope...
}
// I did not leak my integer here! The destructor of unique_ptr called delete

Şimdi unique_ptr, benzersiz mülkiyeti modelleyen akıllı bir işaretçidir, yani programınızda herhangi bir zamanda , sivri uçlu nesneye yalnızca bir (sahip olan) işaretçi olacaktır - bu nedenle unique_ptrkopyalanamaz.

Akıllı işaretçileri, uymanızı gerektirdikleri örtük sözleşmeyi bozmayacak şekilde kullandığınız sürece, hiçbir belleğin sızdırılmayacağına dair garantiye sahip olacaksınız ve nesneniz için uygun sahiplik politikası uygulanacaktır. Ham işaretçiler size bu garantiyi vermez.


3
Merhaba, ben hakkında hiçbir şey anlayamadık model object ownership, integer leakkod veya enforcing ownership policy for object. Bu kavramları öğrenmek için konu / kaynak önerebilir misiniz?
Flame of udun

1
Ben kullanamaz unique_ptrbir hata almadan,: The text ">" is unexpected. It may be that this token was intended as a template argument list terminator but the name is not known to be a template., ben olsa bile #include <utility>ve #include <memory>. Herhangi bir tavsiye?
Anonim

15

Unique_ptr'ye atamanın her iki kavramında da çalışmanın hiçbir farkı yoktur.

int* intPtr = new int(3);
unique_ptr<int> uptr (intPtr);

benzer

unique_ptr<int> uptr (new int(3));

Burada unique_ptr otomatik olarak kapladığı alanı siler uptr.


bu şekilde bildirilen işaretçiler, "normal" bir şekilde bildirilen işaretçilerden farklı olacaktır.

Yığın alanında bir tamsayı oluşturursanız ( yeni anahtar kelime veya malloc kullanarak ), o zaman bu belleği kendi başınıza temizlemeniz gerekir ( sırasıyla silme veya serbest bırakma kullanarak ).

Aşağıdaki kodda,

int* heapInt = new int(5);//initialize int in heap memory
.
.//use heapInt
.
delete heapInt;

Burada, kullanımı bittiğinde heapInt'i silmeniz gerekecek. Silinmezse, bellek sızıntısı meydana gelir.

Böyle bellek sızıntılarını önlemek için unique_ptr kapsam dışına gittiğinde unique_ptr otomatik heapInt tarafından işgal alanı siler kullanılır. Bu nedenle, unique_ptr için silmenize veya serbest bırakmanıza gerek yoktur .


10

Benzersiz işaretçilerin, kapsam dışına çıktıklarında yönettikleri nesneyi yok etmeleri garanti edilir. http://en.cppreference.com/w/cpp/memory/unique_ptr

Bu durumda:

unique_ptr<double> uptr2 (pd);

pduptr2kapsam dışına çıktığında imha edilecek . Bu, otomatik silme ile bellek yönetimini kolaylaştırır.

Durumunda unique_ptr<int> uptr (new int(3));ham işaretçi burada herhangi bir değişkene atanmamış olması dışında, farklı değildir.


-1

Gönderen cppreference , biri std::unique_ptryapıcıları olan

açık benzersiz_ptr (işaretçi p) noexcept;

Yani yeni oluşturmak std::unique_ptr, kurucusuna bir işaretçi iletmektir.

unique_ptr<int> uptr (new int(3));

Ya da aynı

int *int_ptr = new int(3);
std::unique_ptr<int> uptr (int_ptr);

Farklı olan, kullandıktan sonra temizlemek zorunda olmamanızdır. std::unique_ptr(Akıllı işaretçi) kullanmazsanız , bu şekilde silmeniz gerekecektir.

delete int_ptr;

artık ihtiyacınız kalmadığında veya bellek sızıntısına neden olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.