Akıllı işaretçi nedir ve ne zaman kullanmalıyım?


1819

Akıllı işaretçi nedir ve ne zaman kullanmalıyım?



2
Visual Studio 2005'te std :: auto_ptr uygulamasının korkunç bir şekilde bozulduğunu unutmayın. <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842 kullanın yerine artırmak.
Richard

25
Konuyla ilgili iki mükemmel makale: - Akıllı İşaretçiler - Ne, Neden, Hangi? - Haftanın Guru # 25
Lazer

1
İşte Alexandrescu'nun farklı lezzetlerden akıllı işaretçiler yaratmanın azimli cesareti hakkındaki (ücretsiz) bölümü: informit.com/articles/article.aspx?p=31529 Uygulamasında, hangi özellikleri istediğini belirtmek için şablon politikalarını "politikalar" olarak kullanıyor ( örneğin referans sayımı), standart kitaplık ayrı sınıflar kullanır. Ayrıca std :: unique_ptr gibi bir şeyi mümkün kılmak için rvalue referansları bulunmadan önce yazdığını unutmayın.
metal

Yukarıdaki soruya bir puan daha eklemek istiyorum, akıllı işaretçi std :: shared_ptr alt simge operatörü yok ve ponter aritmetiği desteklemiyor, yerleşik bir işaretçi elde etmek için get () kullanabilirsiniz.
suresh m

Yanıtlar:


1883

GÜNCELLEME

Bu cevap oldukça eskidir ve o zaman Boost kütüphanesi tarafından sağlanan akıllı işaretçiler olan 'iyi' olanı açıklar. C ++ 11 yılından bu yana, standart kütüphane yeterli akıllı işaretçileri türlerini sağlamıştır ve böylece kullanma alışkanlığı olmalıdır std::unique_ptr, std::shared_ptrve std::weak_ptr.

Ayrıca vardı std::auto_ptr. Kapsamlı bir işaretçi gibiydi, ancak kopyalanması için "özel" tehlikeli yeteneğe de sahipti - bu da beklenmedik bir şekilde sahipliği devretti.
C ++ 11'de kullanımdan kaldırıldı ve C ++ 17'de kaldırıldı , bu yüzden kullanmamalısınız.

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

ESKİ CEVAP

Akıllı işaretçi, işaretlenen nesnenin ömrünü yönetmek için 'ham' (veya 'çıplak') C ++ işaretçisini saran bir sınıftır. Tek bir akıllı işaretçi türü yoktur, ancak hepsi pratik bir şekilde ham bir işaretçi soyutlamaya çalışır.

Akıllı işaretçiler ham işaretçiler yerine tercih edilmelidir. İşaretçiler kullanmanız gerektiğini düşünüyorsanız (önce gerçekten yaparsanız düşünün ), normalde akıllı bir işaretçi kullanmak istersiniz, çünkü bu ham işaretçilerle ilgili sorunların çoğunu hafifletebilir, özellikle nesneyi silmeyi ve bellek sızıntısını unutur.

Ham işaretçilerle, programcı artık yararlı olmadığında nesneyi açıkça yok etmek zorundadır.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Karşılaştırma ile akıllı bir işaretçi, nesnenin ne zaman imha edildiğine ilişkin bir politika tanımlar. Hâlâ nesneyi yaratmanız gerekiyor, ancak artık nesneyi yok etme konusunda endişelenmenize gerek yok.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

Kullanımdaki en basit politika, boost::scoped_ptrveya tarafından uygulanan gibi akıllı işaretçi sarma nesnesinin kapsamını içerir std::unique_ptr.

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

O Not std::unique_ptrörnekleri kopyalanamaz. Bu, işaretçinin birden çok kez silinmesini (yanlış) önler. Bununla birlikte, aradığınız referansları aradığınız diğer işlevlere iletebilirsiniz.

std::unique_ptrnesnenin ömrünü belirli bir kod bloğuna bağlamak istediğinizde veya başka bir nesneye üye verileri olarak gömdüğünüzde, diğer nesnenin ömründe yararlıdır. Nesne, içeren kod bloğundan çıkılıncaya veya içeren nesne yok oluncaya kadar var olur.

Daha karmaşık bir akıllı işaretçi ilkesi, işaretçiyi saymak için başvuru içerir. Bu, işaretçinin kopyalanmasına izin verir. Nesneye son "başvuru" yok edildiğinde, nesne silinir. Bu politika boost::shared_ptrve tarafından uygulanır std::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Referans sayılan işaretçiler, nesnenizin ömrü çok daha karmaşık olduğunda ve kodun belirli bir bölümüne veya başka bir nesneye doğrudan bağlı olmadığında çok kullanışlıdır.

Sayılan işaretçilerin referansı için bir dezavantaj vardır - sarkan bir referans oluşturma olasılığı:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Başka bir olasılık dairesel referanslar oluşturmaktır:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Bu soruna geçici bir çözüm bulmak için <a0> </a0>, Boost ve C ++ 11 weak_ptrzayıf bir (sayılmamış) bir başvuru tanımlamak için bir tanımladı shared_ptr.


7
Bunun std::auto_ptr<MyObject> p1 (new MyObject());yerine mi demek istiyorsun std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq

35
Müthiş cevap. C ++ 11 için güncellenmiş olsaydı iyi olurdu. Yeni 11 standardı hakkında bilgi arayan bu cevabı buldum ve gelecekteki ziyaretçilerin güncellenmiş bilgileri bulabilmesi güzel olurdu. Auto_ptr'in kullanımdan kaldırıldığını biliyorum. Ben shated_ptr ve poor_ptr açıklandığı gibi var inanıyorum ve scoped_ptr şimdi standard_ptr olduğunu düşünüyorum. Bu doğruysa, lütfen bu cevap güncellenebilir mi?
SaulBack

16
Sarkan bir referans yaratma olasılığının sayılan göstergelere referans vermenin bir dezavantajı olduğunu söylemek kesinlikle deliliktir. Olası sarkan başvurular herhangi bir C ++ işaretçisinin bir dezavantajıdır . Aslında, akıllı işaretçilerin hafifletmeyi amaçladığı dezavantajdır .
Michael Dorst

16
Akıllı işaretçiye bir işaretçiyi bildirirseniz (örnekte yapıldığı gibi) akıllı işaretçinin bilerek tüm avantajlarından vazgeçersiniz. Bu bir dezavantaj veya tasarım hatası değildir, akla gelebilecek en aptalca kullanımdır.
Michael Dorst

3
const std::auto_ptrC ++ 03 ile sıkışıp kalırsanız, A'nın kullanımı güvenlidir. C ++ 11'e erişene kadar pimpl deseni için çok kullandım.
Toby Speight

303

İşte modern C ++ (C ++ 11 ve üstü) günleri için basit bir cevap:

  • Akıllı işaretçi nedir?
    Değerleri işaretçiler gibi kullanılabilen, ancak otomatik bellek yönetiminin ek özelliğini sağlayan bir türdür: Akıllı bir işaretçi artık kullanılmadığında, işaret ettiği bellek yeniden yerleştirilir ( Wikipedia'da daha ayrıntılı tanıma da bakın ).
  • Ne zaman kullanmalıyım?
    Bir bellek parçasının sahipliğini izlemeyi, tahsis etmeyi veya tahsis etmemeyi içeren kodda; akıllı işaretçi genellikle bunları açıkça yapma ihtiyacınızı ortadan kaldırır.
  • Ama bu durumlarda hangi akıllı işaretçiyi kullanmalıyım?
    • Kullan std::unique_ptrAynı nesneye birden başvuruları tutma niyetinde olmadığı zaman. Örneğin, bir kapsam girerken ayrılan ve kapsamdan çıkıldığında ayrılan belleğe bir işaretçi için kullanın.
    • Kullanım std::shared_ptryapmanız birden fazla yerden sizin nesneye başvurmak istediğinizde - ve tüm bu referanslar gitmiş kendilerini olana kadar nesne de-tahsis olmak istemiyorum.
    • Kullanım std::weak_ptrbunun (onlar sadece nesne dereference çalıştığınızda gitmiş dikkat edeceğiz böylece) görmezden ve geri_ver için ok kendisi için referanslara - yapmanız birden fazla yerden sizin nesneye başvurmak istediğinizde.
    • boost::Akıllı işaretçileri kullanmanız veya std::auto_ptrgerekmesi durumunda okuyabileceğiniz özel durumlar dışında kullanmayın .
  • Hey, hangisini kullanacağımı sormadım!
    Ah, ama gerçekten itiraf etmek istedin.
  • O zaman ne zaman düzenli işaretçiler kullanmalıyım?
    Çoğunlukla bellek sahipliğinden habersiz olan kodda. Bu, tipik olarak, başka bir yerden bir işaretçi alan ve ayırmayan veya ayırmayan ve işlevlerini yürüten göstericinin bir kopyasını saklamayan işlevlerde olur.

5
Akıllı (sahip) işaretçiler uygun bellek yönetimine yardımcı olurken, ham (sahip olmayan) işaretçilerin veri yapılarındaki diğer organizasyon amaçları için hala yararlı olduğunu belirtmek gerekir. Herb Sutter, CppCon 2016'da YouTube'da görebileceğiniz harika bir sunum yaptı: C ++ 'da Sızıntı Özgürlüğü ... Varsayılan olarak.
wiktor.wandachowicz

1
@ wiktor.wandachowicz T*etmektir std::unique_ptr<T>nedir std::weak_ptr<T>etmektirstd::shared_ptr<T>
Caleth

@Caleth: Hayır, bunu söylemezdim.
einpoklum

1
@TonyTannous: Saygı ile - Büyük bir düzenlemeydi; ve soyut olan cevabımın buna ihtiyacı olduğunu hissetmiyorum. Örneği bir yorumda bağlantısıyla ayrı bir cevap yapmanızı öneririm.
einpoklum

112

Akıllı işaretçi , otomatik bellek dağıtımı, referans sayımı vb. Gibi bazı ek işlevlere sahip işaretçi benzeri bir türdür.

Küçük giriş sayfasında bulunabilir Akıllı İşaretçiler - Ne, Neden, Hangi? .

Basit akıllı işaretçi türlerinden biri std::auto_ptr (C ++ standardının 20.4.5 bölümü), hafızanın kapsam dışındayken otomatik olarak yeniden yerleştirilmesine izin veren ve daha az esnek olmasına rağmen, istisnalar atıldığında basit işaretçi kullanımından daha sağlam olanıdır.

Başka bir uygun tip, boost::shared_ptrreferans sayımını uygulayan ve nesneye hiçbir referans kalmadığında otomatik olarak belleği yeniden yerleştirir. Bu, bellek sızıntılarını önlemeye yardımcı olur ve uygulanması kolaydır RAII .

Konu, David Vandevoorde, Nicolai M. Josuttis tarafından yazılan "C ++ Templates: The Complete Guide" kitabında ayrıntılı olarak ele alınmıştır. , bölüm Bölüm 20. Akıllı İşaretçiler . Kapsanan bazı konular:

  • İstisnalara Karşı Koruma
  • Tutucular, (not, std :: auto_ptr bu tür akıllı işaretçilerin uygulanmasıdır)
  • Kaynak Edinimi Başlatılıyor (Bu genellikle C ++ 'da istisna açısından güvenli kaynak yönetimi için kullanılır)
  • Tutucu Sınırlamaları
  • Referans Sayımı
  • Eşzamanlı Sayaç Erişimi
  • Yıkım ve Düşüş

2
std::auto_ptrSahipliği yanlışlıkla aktarabileceğiniz için uyarı onaylanmadı ve son derece cesaret kırıcı. - C ++ 11 Boost, kullanım ihtiyacı ortadan kaldırır: std::unique_ptr, std::shared_ptrvestd::weak_ptr
ninMonkey

42

Chris, Sergdev ve Llyod tarafından sağlanan tanımlar doğrudur. Daha basit bir tanımlamayı tercih ediyorum, sadece hayatımı basit tutmak için: Akıllı bir işaretçi -> ve *operatörleri aşırı yükleyen bir sınıftır . Senin nesne semantik bir işaretçi gibi görünüyor ama bunu referans sayma, otomatik imha vb dahil yolu soğutucu şeyler yapmak yapabileceği hangi araçlar shared_ptrve auto_ptrçoğu durumda yeterlidir, ama küçük huyların kendi seti ile birlikte geliyor.


30

Akıllı işaretçi, "char *" gibi normal bir işaretçi gibi, işaretçinin kendisi kapsam dışına çıktığında işaret ettiği şey de silinir. "->" kullanarak normal bir işaretçi gibi kullanabilirsiniz, ancak veriler için gerçek bir işaretçiye ihtiyacınız varsa kullanamazsınız. Bunun için "& * ptr" kullanabilirsiniz.

Aşağıdakiler için yararlıdır:

  • Yeni ile tahsis edilmesi gereken, ancak bu yığındaki bir şeyle aynı ömre sahip olmak istediğiniz nesneler. Nesne akıllı bir işaretçiye atanırsa, program bu işlevden / bloktan çıktığında silinir.

  • Sınıfların veri üyeleri, böylece nesne silindiğinde, sahip olunan tüm veriler de, yıkıcıda herhangi bir özel kod olmadan silinir (yıkıcının sanal olduğundan emin olmanız gerekir, bu da her zaman yapılacak iyi bir şeydir) .

Sen olabilir değil zaman akıllı işaretçi kullanmak istiyorum:

  • ... imleç aslında verilere sahip olmamalıdır ... yani, sadece verileri kullandığınızda, ancak referansta bulunduğunuz fonksiyonda hayatta kalmasını istiyorsunuz.
  • ... akıllı işaretçinin kendisi bir noktada yok edilmeyecek. Asla yok edilmeyen bir bellekte oturmasını istemezsiniz (dinamik olarak ayrılmış ancak açıkça silinmeyecek bir nesne gibi).
  • ... iki akıllı işaretçi aynı verilere işaret edebilir. (Bununla birlikte, bunu ele alacak daha akıllı işaretçiler bile vardır ... buna referans sayımı denir .)

Ayrıca bakınız:


18

Çoğu akıllı işaretçi sizin için işaretçiyi-nesnenin atılmasını sağlar. Çok kullanışlıdır, çünkü artık nesneleri manuel olarak elden çıkarmayı düşünmek zorunda değilsiniz.

En yaygın kullanılan akıllı işaretçiler std::tr1::shared_ptr(veya boost::shared_ptr) ve daha az yaygın olanlardır std::auto_ptr. Düzenli kullanımını tavsiye ederimshared_ptr .

shared_ptrçok yönlüdür ve nesnelerin "DLL sınırlarının ötesine geçmesi" gereken durumlar ( libckodunuz ve DLL'ler arasında farklı s kullanılması durumunda yaygın kabus durumu) dahil olmak üzere çok çeşitli bertaraf senaryolarıyla ilgilenir .


18

Akıllı işaretçi, işaretçi gibi davranan, ancak ek olarak inşaat, imha, kopyalama, taşıma ve kayıttan çıkarma üzerinde denetim sağlayan bir nesnedir.

Biri kendi akıllı işaretçisini uygulayabilir, ancak birçok kütüphane aynı zamanda her biri farklı avantaj ve dezavantajlara sahip akıllı işaretçi uygulamaları sağlar.

Örneğin, Boost aşağıdaki akıllı işaretçi uygulamalarını sağlar:

  • shared_ptr<T>Tnesnenin artık ne zaman gerekli olmadığını belirlemek için bir referans sayısı kullanma işaretçisidir .
  • scoped_ptr<T>kapsam dışına çıktığında otomatik olarak silinen bir işaretçi. Atama yapılamaz.
  • intrusive_ptr<T>başka bir referans sayma işaretçisidir. Daha iyi performans sağlar shared_ptr, ancak türün Tkendi referans sayma mekanizmasını sağlamasını gerektirir .
  • weak_ptr<T>shared_ptrdairesel referanslardan kaçınmak için birlikte çalışan zayıf bir göstericidir .
  • shared_array<T>gibidir shared_ptr, ancak dizileri için T.
  • scoped_array<T>gibidir scoped_ptr, ancak dizileri için T.

Bunlar her birinin sadece bir doğrusal açıklamasıdır ve ihtiyaca göre kullanılabilir, daha fazla ayrıntı ve örnek için Boost'un belgelerine bakabilirsiniz.

Ayrıca, C ++ standart kitaplığı üç akıllı işaretçi sağlar; std::unique_ptrbenzersiz sahiplik, std::shared_ptrpaylaşılan sahiplik ve std::weak_ptr. std::auto_ptrC ++ 03'te mevcuttu ancak artık kullanımdan kaldırıldı.


Lütfen neden scoped_ptryerel olarak beyan edilmediğini açıklayın const unique_ptr- kapsamdan çıkıldığında da silinir.
einpoklum

11

İşte benzer cevaplar için Bağlantı: bağlantısı http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Akıllı işaretçi, normal bir işaretçi gibi davranan, görünen ve hisseden ancak daha fazla işlevsellik sunan bir nesnedir. C ++ 'da, akıllı işaretçiler bir işaretçiyi kapsülleyen ve standart işaretçi işleçlerini geçersiz kılan şablon sınıfları olarak uygulanır. Düzenli göstergelere göre bir takım avantajları vardır. Null işaretçileri veya bir yığın nesnesine işaretçiler olarak başlatılmaları garanti edilir. Boş gösterici üzerinden aktarım kontrol edilir. Hiçbir zaman silmek gerekmez. Nesneler, son işaretçisi gittiğinde otomatik olarak serbest bırakılır. Bu akıllı işaretçilerle ilgili önemli bir sorun, normal işaretçilerin aksine kalıtıma saygı göstermemesidir. Akıllı işaretçiler polimorfik kod için çekici değildir. Aşağıda akıllı işaretçilerin uygulanması için bir örnek verilmiştir.

Misal:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Bu sınıf, X tipi bir nesneye akıllı bir işaretçi uygular. Nesnenin kendisi yığın üzerinde bulunur. İşte nasıl kullanılır:

smart_pointer <employee> p= employee("Harris",1333);

Aşırı yüklenmiş diğer operatörler gibi p de normal bir işaretçi gibi davranacaktır,

cout<<*p;
p->raise_salary(0.5);

9

http://en.wikipedia.org/wiki/Smart_pointer

Bilgisayar biliminde akıllı işaretçi, otomatik çöp toplama veya sınır denetimi gibi ek özellikler sağlarken işaretçiyi simüle eden soyut bir veri türüdür. Bu ek özellikler, verimliliği korurken işaretçilerin yanlış kullanımından kaynaklanan hataları azaltmayı amaçlamaktadır. Akıllı işaretçiler genellikle bellek yönetimi amacıyla kendilerini işaret eden nesneleri izler. İşaretçilerin kötüye kullanılması önemli bir hata kaynağıdır: işaretçiler kullanılarak yazılmış bir program tarafından yapılması gereken sabit ayırma, yeniden konumlandırma ve referans, bazı bellek sızıntılarının oluşmasını büyük olasılıkla mümkün kılar. Akıllı işaretçiler, kaynak ayırmayı otomatik hale getirerek bellek sızıntılarını önlemeye çalışır: bir nesneye işaretçi (veya bir dizi işaretçideki son) yok edildiğinde,


6

T bu öğreticide bir sınıf olsun C ++ işaretçiler 3 tipe ayrılabilir:

1) Ham işaretçiler :

T a;  
T * _ptr = &a; 

Hafıza adresini hafızadaki bir yere tutarlar. Programları takip etmek zorlaştıkça dikkatli kullanın.

Sabit veri veya adrese sahip işaretçiler {Geriye doğru okuyun}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Sabit bir veri türü T olan işaretçi. Yani işaretçiyi kullanarak veri türünü değiştiremezsiniz. yani *ptr1 = 19; çalışmayacak. Ancak işaretçiyi hareket ettirebilirsiniz. yani ptr1++ , ptr1--; vb çalışacaktır. Geriye doğru okuyun: const olan T tipine işaretçi

  T * const ptr2 ;

T veri tipine ilişkin sabit bir işaretçi. Yani işaretçiyi hareket ettiremezsiniz ancak işaretçinin işaret ettiği değeri değiştirebilirsiniz. yani *ptr2 = 19işe yarayacak ama ptr2++ ; ptr2--vb işe yaramayacak. Geriye doğru okuyun: T türüne sabit gösterici

const T * const ptr3 ; 

Sabit veri türü T için bir sabit işaretçi. Yani işaretçiyi hareket ettiremezsiniz ya da veri türü işaretçisini işaretçi olarak değiştiremezsiniz. yani. ptr3-- ; ptr3++ ; *ptr3 = 19;çalışmayacak

3) Akıllı İşaretçiler : { #include <memory>}

Paylaşılan İşaretçi :

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

İşaretçinin işaret ettiği nesneye kaç "şeyin" işaret ettiğini izlemek için referans sayımı kullanılarak uygulanır. Bu sayı 0 olduğunda, nesne otomatik olarak silinir, yani nesneyi işaret eden tüm share_ptr kapsam dışında kaldığında nesne silinir. Bu, yeni kullanarak ayırdığınız nesneleri silmek zorunda kalmanın baş ağrısından kurtulur.

Zayıf İşaretçi: Paylaşılan İşaretçi kullanılırken ortaya çıkan döngüsel referansla başa çıkmanıza yardımcı olur İki paylaşılan işaretçi tarafından işaretlenmiş iki nesneniz varsa ve birbirlerinin paylaşılan işaretçisine işaret eden dahili bir paylaşılan işaretçi varsa, döngüsel bir referans olur ve nesne paylaşılan işaretçiler kapsam dışına çıktığında silinir. Bu sorunu çözmek için, iç üyeyi paylaşılan_ptr değerinden zayıf_ptr değerine değiştirin. Not: Zayıf bir işaretçinin işaret ettiği öğeye erişmek için lock () kullanın, bu bir zayıf_ptr döndürür.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

Bakınız: std :: poor_ptr ne zaman yararlıdır?

Benzersiz İşaretçi: Özel mülkiyet ile hafif akıllı işaretçi. İşaretçi nesneleri işaretçiler arasında paylaşmadan benzersiz nesnelere işaret ettiğinde kullanın.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Benzersiz ptr ile gösterilen nesneyi değiştirmek için taşıma semantiğini kullanın

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Referanslar: Temelde sabit işaretçiler olarak düşünülebilir, yani sabit olan ve daha iyi sözdizimi ile hareket ettirilemeyen bir işaretçi.

Bkz: C ++ 'da işaretçi değişkeni ile başvuru değişkeni arasındaki farklar nelerdir?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Referans: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Bu soruyu işaret ettiği için Andre'ye teşekkür ederiz.


3

Akıllı işaretçi bir sınıftır, normal bir işaretçinin sarıcısıdır. Normal işaretçilerin aksine, akıllı noktanın yaşam döngüsü bir referans sayısına dayanır (akıllı işaretçi nesnesinin kaç kez atandığı). Dolayısıyla, bir akıllı işaretçi diğerine atandığında, dahili referans sayısı artı artı. Ve nesne kapsam dışına çıktığında, referans sayısı eksi eksi.

Otomatik işaretçi, benzer görünse de, akıllı işaretçiden tamamen farklıdır. Bir otomatik işaretçi nesnesi değişken kapsam dışına çıktığında kaynağı yeniden dağıtan uygun bir sınıftır. Bir dereceye kadar, bir işaretçi (dinamik olarak ayrılan belleğe) bir yığın değişkenine benzer şekilde çalışır (derleme zamanında statik olarak ayrılır).


2

Akıllı İşaretçiler, Bellek Ayırma, Kaynak Paylaşımı ve Aktarma konusunda endişelenmenize gerek olmayanlardır.

Bu işaretçiyi Java'da herhangi bir ayırma işlemine benzer şekilde çok iyi kullanabilirsiniz. Java Çöp Toplayıcı hile yapar, Akıllı İşaretçiler ise hile Destructors tarafından yapılır.


1

Mevcut cevaplar iyidir, ancak akıllı bir işaretçi çözmeye çalıştığınız sorunun (tam) cevabı olmadığında ne yapacağınızı kapsamaz.

Diğer şeylerin yanı sıra (diğer cevaplarda da iyi açıklanmıştır) akıllı bir işaretçi kullanmak, soyut bir sınıfı işlev dönüş tipi olarak nasıl kullanabiliriz? bu sorunun bir kopyası olarak işaretlenmiştir. Ancak, bir soyut (veya aslında herhangi bir) temel sınıfı C ++ 'da bir dönüş türü olarak belirtmek isteyip istemediğinizi soran ilk soru "gerçekten ne demek istiyorsun?" C ++ 'da deyimsel nesne yönelimli programlama (ve bunun diğer dillerden nasıl farklı olduğu) hakkında boost pointer konteyner kütüphanesinin belgelerinde iyi bir tartışma (daha fazla referansla) vardır.. Özetle, C ++ ile sahiplik hakkında düşünmeniz gerekir. Hangi akıllı işaretçiler size yardımcı olur, ancak tek çözüm değildir veya her zaman tam bir çözüm değildir (size polimorfik kopya vermezler) ve her zaman arayüzünüzde ortaya çıkarmak istediğiniz bir çözüm değildir (ve bir işlev geri dönüşü korkunç bir ses çıkarır) bir arayüz gibi). Örneğin, bir referans döndürmek yeterli olabilir. Ancak tüm bu durumlarda (akıllı işaretçi, işaretçi kabı veya basitçe bir referans döndürme), dönüşü bir değerden bir referans biçimine değiştirdiniz. Eğer gerçekten kopyaya ihtiyacınız varsa, daha fazla kaynak plakası "deyim" eklemeniz veya Adobe veya ++ gibi kitaplıkları kullanarak C ++ 'daki deyimsel (veya başka türlü) OOP'un ötesine geçmeniz gerekebilir Boost plaka OOP'un ötesine geçmeniz gerekebilir..

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.