std :: shared_ptr bunun


104

Şu anda akıllı işaretçilerin nasıl kullanılacağını öğrenmeye çalışıyorum. Ancak bazı deneyler yaparken doyurucu bir çözüm bulamadığım şu durumu keşfettim:

B sınıfından bir nesnenin (çocuk) ebeveyni olan A sınıfı bir nesneniz olduğunu düşünün, ancak her ikisi de birbirini tanımalıdır:

class A;
class B;

class A
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children->push_back(child);

        // How to do pass the pointer correctly?
        // child->setParent(this);  // wrong
        //                  ^^^^
    }

private:        
    std::list<std::shared_ptr<B>> children;
};

class B
{
public:
    setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    };

private:
    std::shared_ptr<A> parent;
};

Soru, A sınıfının bir nesnesinin std::shared_ptrkendisinden a'yı ( this) çocuğuna nasıl geçirebileceğidir ?

Orada (Boost paylaşılan işaretçileri için çözümleridir bir Başlarken boost::shared_ptriçinthis ), ancak bu nasıl kullanarak işlemek için std::akıllı işaretçiler?


2
Diğer herhangi bir araçta olduğu gibi, uygun olduğunda onu kullanmanız gerekir. Yaptığınız şey için akıllı işaretçiler kullanmak değil
YePhIcK

Arttırmaya benzer şekilde. Buraya bakın .
juanchopanza

1
Bu soyutlama düzeyindeki bir sorundur. "Bu" nun yığın üzerindeki hafızayı gösterdiğini bile bilmiyorsunuz.
Vaughn Cato

Dil bilmiyor ama sen yapıyorsun. Neyin nerede olduğunu takip ettiğiniz sürece, iyi olacaksınız.
Alex

Yanıtlar:


173

Orada std::enable_shared_from_thissadece bu amaç için. Ondan miras alırsınız .shared_from_this()ve sınıfın içinden arayabilirsiniz . Ayrıca, burada kaynak sızıntılarına neden olabilecek döngüsel bağımlılıklar oluşturuyorsunuz. Bu, kullanımı ile çözülebilir std::weak_ptr. Dolayısıyla kodunuz şöyle görünebilir (çocukların ebeveynin varlığına güvendiklerini ve tersi olmadığını varsayarak):

class A;
class B;

class A
    : public std::enable_shared_from_this<A>
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children.push_back(child);

        // like this
        child->setParent(shared_from_this());  // ok
        //               ^^^^^^^^^^^^^^^^^^
    }

private:     
    // note weak_ptr   
    std::list<std::weak_ptr<B>> children;
    //             ^^^^^^^^
};

class B
{
public:
    void setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    }

private:
    std::shared_ptr<A> parent;
};

Ancak, aramanın arama noktasında sahibi .shared_from_this()olmasını gerektirdiğini unutmayın . Bu, artık yığın üzerinde böyle bir nesne oluşturamayacağınız ve genellikle bir kurucu veya yıkıcı içinden çağrı yapamayacağınız anlamına gelir .thisstd::shared_ptr.shared_from_this()


2
Açıklamanız ve döngüsel bağımlılık sorunuma işaret ettiğiniz için teşekkür ederim.
Icarus

@Deduplicator ne demek istiyorsun?
yuri kilochek

1
@Deduplicator bu bir, pardon my pardon, oldukça anlamsız paylaşılan işaretçi. Bu kurucunun, yönetilen nesnenin üyelerine veya tabanlarına işaretçilerle kullanılması amaçlanmıştır. Her durumda ne demek istiyorsun (üzgünüm)? Bu sahip olmayan e-postalar shared_ptrbu soruyla alakasızdır. shared_from_this'ın önkoşulları, nesnenin shared_ptrarama anında bazıları tarafından sahiplenilmesi (sadece işaret edilmemesi) gerektiğini açıkça belirtir .
yuri kilochek

1
@kazarey a tarafından sahip olunması shared_ptrçağrı noktasında gereklidir, ancak tipik bir kullanım modelinde, yani benzeri bir şey shared_ptr<Foo> p(new Foo());, shared_ptrancak tamamen oluşturulduktan sonra nesnenin sahipliğini üstlenir. Bunu, shared_ptrkurucu ile başlatılan thisve onu yerel olmayan bir yerde (örneğin bir referans argümanında) saklayarak, böylece kurucu tamamlandığında ölmeyerek aşmak mümkündür . Ancak bu kıvrımlı senaryonun gerekli olması pek olası değildir.
yuri kilochek

1
OP'lerin sorusunu yanıtladığı için bu yanıta bir sayım verdi. "Daha iyi yolu" önermeyenler çoğu kez yanılıyorlar. Ayrıca, bir sorun için bu cevaba ihtiyacım olduğu için bir sayım yaptım. Birçok kez kullandığım bir deyim, tüm sınıf örneklerinin tam bir listesini elde etmek için bir kaba "this" koymaktır, yani her örneği işlemek için kapsayıcıda gezinmek. Lütfen bunun neden sorunlu olduğunu açıklamaya çalışmayın. Sorunları ve onlardan nasıl kaçınılacağını biliyorum.
rm1948

8

Tasarımınızda, akıllı işaretçilerin yanlış anlaşılmasından kaynaklanıyor gibi görünen birkaç probleminiz var.

Sahipliği bildirmek için akıllı işaretçiler kullanılır. Bunu, hem ebeveynin tüm çocuklara sahip olduğunu hem de her çocuğun kendi ebeveynine sahip olduğunu beyan ederek bozuyorsunuz. İkisi de doğru olamaz.

Ayrıca, zayıf bir göstericiye geri dönüyorsunuz getChild(). Bunu yaparak, arayanın sahipliği önemsememesi gerektiğini beyan etmiş olursunuz. Şimdi bu çok sınırlayıcı olabilir, ancak bunu yaparak, söz konusu çocuğun zayıf işaretçiler hala tutulurken yok edilmediğinden emin olmalısınız, akıllı bir işaretçi kullanırsanız, kendi kendine çözülür. .

Ve son şey. Genellikle, yeni varlıkları kabul ettiğinizde, genellikle ham işaretçileri kabul etmelisiniz. Akıllı işaretçi, çocukları ebeveynler arasında değiştirmek için kendi anlamlarına sahip olabilir, ancak genel kullanım için ham işaretçileri kabul etmelisiniz.


Görünüşe göre akıllı işaretçilerle ilgili anlayışımı gerçekten netleştirmem gerekiyor. Bunu belirttiğiniz için teşekkür ederim.
Icarus
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.