SORU
1 EYLÜL 2009, Salı


C Nesnelere İşaretçiler Vektör

Nesnelere işaretçiler vektör kullanıyorum. Bu nesneler temel bir sınıf türetilir, ve dinamik olarak ayrılan ve saklanan ediliyor.

Örneğin, gibi bir şey var:

vector<Enemy*> Enemies;

ve bu gibi Düşman sınıf ve dinamik olarak türetilmiş sınıf için bellek ayrılırken sonra türetmek, olmam

enemies.push_back(new Monster());

Bellek sızıntıları ve diğer sorunları önlemek için dikkat etmem gereken şeyler nelerdir?

CEVAP
1 EYLÜL 2009, Salı


std::vector hafızası, her zamanki gibi yönetecek, ama bu bellek işaretçiler, nesneleri değil.

Bu ne demek, sınıfları bellekte kaybolur. vektör kapsam dışına gider sonra. Örneğin:

#include <vector>

struct base
{
    virtual ~base() {}
};

struct derived : base {};

typedef std::vector<base*> container;

void foo()
{
    container c;

    for (unsigned i = 0; i < 100;   i)
        c.push_back(new derived());

} // leaks here! frees the pointers, doesn't delete them (nor should it)

int main()
{
    foo();
}

Yapmanız gereken şey ise, vektör kapsam dışına gitmeden önce tüm nesneleri silmek emin olun

#include <algorithm>
#include <vector>

struct base
{
    virtual ~base() {}
};

struct derived : base {};

typedef std::vector<base*> container;

template <typename T>
void delete_pointed_to(T* const ptr)
{
    delete ptr;
}

void foo()
{
    container c;

    for (unsigned i = 0; i < 100;   i)
        c.push_back(new derived());

    // free memory
    std::for_each(c.begin(), c.end(), delete_pointed_to<base>);
}

int main()
{
    foo();
}

Bu eylemi gerçekleştirmek için hatırlamak zorunda çünkü bakımı zor olsa da. Eğer bir istisna arasında elementlerin ayırma ve kaldırma döngü ortaya çıkması halinde daha da önemlisi, kaldırma döngü asla neyse bellek sızıntısı kaldın ve çalıştırın! Bu durum, güvenlik denir ve kaldırma otomatik olarak yapılması gereken kritik bir sebep.

İyi işaretçiler kendilerini silinmiş olacaktır. Tezler akıllı işaretçiler olarak adlandırılır ve standart kütüphane std::unique_ptr std::shared_ptr sağlar.

std::unique_ptr bazı kaynak (paylaşılmayan, tek sahibi) benzersiz bir işaretçi temsil eder. Bu akıllı işaretçi, ve genel olarak tam yerine herhangi bir ham işaretçi kullanın sizin varsayılan olmalıdır.

auto myresource = /*std::*/make_unique<derived>(); // won't leak, frees itself

std::make_unique üst yönetim tarafından C 11 standart eksik, ama bir kendiniz yapabilirsiniz. Doğrudan unique_ptr (eğer varsa make_unique üzerinde tavsiye edilmez) oluşturmak için şunu yapın:

std::unique_ptr<derived> myresource(new derived());

Benzersiz işaretçileri yalnızca semantik bir hareket var; kopyalanamaz:

auto x = myresource; // error, cannot copy
auto y = std::move(myresource); // okay, now myresource is empty

Ve bu bir kabın içinde kullanmamız gereken:

#include <memory>
#include <vector>

struct base
{
    virtual ~base() {}
};

struct derived : base {};

typedef std::vector<std::unique_ptr<base>> container;

void foo()
{
    container c;

    for (unsigned i = 0; i < 100;   i)
        c.push_back(make_unique<derived>());

} // all automatically freed here

int main()
{
    foo();
}

shared_ptr referans sayma kopya semantiği vardır; birden fazla sahipleri nesne paylaşımı sağlar. Kaç shared_ptrs bir nesne için var, parça ve sonuncusu yok (sayım sıfıra gider) durduğunda, işaretçi açığa çıkar. Kopyalama sadece başvuru sayısı (ve neredeyse ücretsiz daha düşük bir maliyetle transfer sahipliğini hareketli) artar. Yaptığınız onlarla std::make_shared (veya doğrudan yukarıda gösterildiği gibi, ama, çünkü shared_ptr içten olun ayırma, genellikle daha verimli ve teknik olarak çok özel durum-Güvenli kullanım make_shared).

#include <memory>
#include <vector>

struct base
{
    virtual ~base() {}
};

struct derived : base {};

typedef std::vector<std::shared_ptr<base>> container;

void foo()
{
    container c;

    for (unsigned i = 0; i < 100;   i)
        c.push_back(std::make_shared<derived>());

} // all automatically freed here

int main()
{
    foo();
}

Unutmayın, genellikle daha hafif, çünkü varsayılan olarak std::unique_ptr kullanmak istiyor. Ayrıca, std::shared_ptr std::unique_ptr (ama tam tersi) dışında inşa edilebilir, Tamam, küçük başlamak en iyisi.

Alternatif olarak, bir kap nesnelere işaretçiler saklamak için oluşturulmuş, boost::ptr_container gibi kullanabilirsiniz:

#include <boost/ptr_container/ptr_vector.hpp>

struct base
{
    virtual ~base() {}
};

struct derived : base {};

// hold pointers, specially
typedef boost::ptr_vector<base> container;

void foo()
{
    container c;

    for (int i = 0; i < 100;   i)
        c.push_back(new Derived());

} // all automatically freed here

int main()
{
    foo();
}

boost::ptr_vector<T> açık kullan C 03, konuşamam alaka şimdi? çünkü biz kullanmak std::vector<std::unique_ptr<T>> ile muhtemelen çok az karşılaştırılabilir Tepegöz, ama bu iddiayı test edilmelidir.

Ne olursa olsun,kodunuzda asla açıkça bir şey. Şeyler kaynak yönetimi otomatik olarak dağıtılır emin olmak için sarın. Kodunuzda herhangi bir raw sahibi olmanın püf noktası var.

Bir oyunda varsayılan olarak, muhtemelen std::vector<std::shared_ptr<T>> ile giderdim. Profil aksi halde, güvenli ve kullanımı kolay olduğunu söylüyor kadar yeterince hızlı zaten, paylaşım bekliyoruz.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Kap Slap

    Kap Slap

    8 Mart 2010
  • Kevin Bruckert

    Kevin Brucke

    30 Aralık 2006
  • thewinekone

    thewinekone

    17 Aralık 2005