2009-12-18 25 views
8

Bir bellek sızıntısı araştırıyorum ve gördüğüm kadarıyla, sorun şuna benzer: // kod comment AtC++ - acemi soru

int main(){ 
    char *cp = 0; 
    func(cp); 
    //code 
    delete[] cp; 
} 

void func(char *cp){ 
    cp = new char[100]; 
} 

, ben cp beklenen Ayrılmış belleğe işaret eder, ancak hala belleği silmemem anlamına gelen boş bir işaretçidir. Ne yapıyorum ben wroing?

+1

"cbuf" unun cp olduğunu varsayalım mı? – GManNickG

+0

gerçek kodu belirleme hakkında. Kod kesilip yapıştırılmadıkça, hata eklemenizin olasılığı vardır. Bu sadece thigs daha zor hale getirir ve biz cbuf gibi kesme ve paster hataları çözme sona erer -> cp –

+0

Bunun için özür dilerim, bir dahaki sefere bunu aklımda tutacağım. Evet cbuf cp –

cevap

11
void func(char *cp){ 
    cp = new char[100]; 
} 

, char * cp ne aynı bellek adresi işaret ediyor ancak aynı işaretçi olmadığı anlamına gelmektedir, bir "kopya ile geçirilen işaretçi" dir. İşaretçiyi içinde değiştirdiğinizde, başka bir yere işaret ettiğinde, aktarılan özgün işaretçi 0'a işaretlemeye devam edecektir.

+0

Teşekkürler, iyi çözüldü. Çok açık bir açıklama. –

+0

@David: Teşekkürler :) –

6

cp parametresi, işlevin yerel bir değişkendir - değiştiğinde, işlev dışındaki hiçbir şeyi değiştirmez. fonksiyonunu yazmak için daha iyi bir yolu şudur:

char * func(){ 
    return new char[100]; 
} 

Ve sorunuza doğrudan yapmak, ancak muhtemelen oldukça dinamik olarak ayrılmış diziler daha std :: string ve std :: vektörü kullanarak olmalıdır.

+1

Hmm, iki downvotes olması gerekiyordu. Özellikle önemsediğimden değil, buradakilerin neyin yanlış olduğunu bilmekten başkaları faydalanabilir. –

+0

Görebileceğim hiçbir şey yok. Bahsettiğiniz C++ özellikleri gibi bir şeye işaret edecekseniz, büyük olasılıkla dizi büyüklüğünü kodlama konusunda bir parça eklemenin iyi olacağını düşünüyorum. Ayrıca, eğer bu özellikleri kullanacaksanız, muhtemelen oluşturmak için bir işaretçiyi birer birer iletmek isteyebilirsiniz ya da kopya oluşturucu cezasından kaçınmak için referans olarak önceden oluşturulmuş bir iletiyi geçirebilirsiniz ... Bu cevapla YANLIŞ bir şey yok. –

+0

İşaretçilerde bir kopya kurucusu yok. –

16

Atanan belleğin değerini cp atamanız gerekir. Ancak, bu yığında bir değişken: ana cp bir kopyası! cp bulunduğunuz işlevine yerel

Ne istediğiniz bir referanstır.:. Bu geçirilen parametre olarak cp diğer ad olacak

void func(char *& cp) 

Sen cbuf yılında geçiyoruz

1

cp değil. Bu işlevde

+0

, * cp iletiyor olsa bile, // kodu –

+1

'dan sonra 0'a işaret eder. Bu önemli değil, çünkü aynı zamanda değeri de geçiriyorsunuz. – mob

1

Bu işlev yalnızca cp'un bir KOPY'sunu değiştirmektedir. Bunun yerine bir referans kullanın.

0

Gman ve Neil de belirtildiği gibi, hiç fonk değişmek zorunda kalacaktır çalışmak için: En acil sorunu çözecektir

char* func();

veya

void func(char*& p);.

Bununla birlikte, bir bakım sorunu vardır. Her iki durumda da, func bir işaretçi döndürür. Func kullanıcısı için net olmayan şey, döndürülen işaretçinin silinmesi gerektiğidir. Bu nedenle, genellikle% 100 gerekli olmadıkça bu yapıdan kaçının. Aksine:

  1. Yardım Kullanıcı daha sonra
  2. ayrılan bellek depolamak için bir nesne kullanın fonk geçirilen bellek doğru miktarda tahsis. Nesne daha sonra imha edildiğinde karakter dizisini silebilir.

Yani C++ kodu için, ben tavsiye ederim:


class CBuf 
{ 
public 
    CBuf() 
    { 
     iBuf = new char[100]; 
    } 
    ~CBuf 
    { 
     delete[] iBuf; 
    } 
    char* func() 
    { 
     //do stuff; 
     return iBuf; 
    } 
private: 
    char* iBuf; 
}; 

int main() 
    { 
    CBuf cb; 
    char* mychar = cb.func(); 
    //do stuff with character array 

    //destructor gets called here because cb goes out of scope 
    } 

Ancak C programlama özellikle, dizi oluşturmak için bir çeşit fonksiyonu var% 100 gerekli olabilir. Bu nedenle C programlamasında, bir CreateCBuf ve DestroyCBuf fonksiyonu ile yıkıcıyı değiştirebilirsiniz. Bu şekilde kütüphanenizin kullanıcısı, iade edilen tamponun imha edilmesi gerektiğini bilir. referanslar sezgisel soyutlama sunan harika olmasına rağmen

+0

std :: vector' ile neyin yanlış olduğunu sorabilir miyim? – GManNickG

+0

std: vektör iyi. Tüm bellek yönetimini sizin için halleder. OP'lerin örneğindeki sorun, sahipliğin çok belirsiz olmasıdır. – doron

1

, örnekleri vardır onlar (why is a reference considered safer than a pointer yani) Herhangi güvenliğini sağlamak ileri sürülebilir fonksiyon zincirleme (ve diğer ezoterik kodlama) izin vermek C++ 11 rvalue referansları ile daha da geliştirilmiş Yukarıda işaretçiyi işlev argümanına bir işaretçi ile çözmek daha iyidir. ansi c ve C++ 'da benzer bir kod tabanına sahip olma ihtiyacı olduğunda. Tabii

#include <iostream> 

using namespace std; 

void func(char ** cp) { 
    *cp = new char[100]; 
    //do something useful 
    (*cp)[0] = 'A'; 
} 

void func(char *& cp) { 
    cp = new char[100]; 
    //do something useful 
    cp[0] = 'B'; 
} 

int main(int argc, char** argv) { 
    char * cp; 
    //pointer to pointer 
    func(&cp); 
    cout << "Index 0 : " << cp[0] << '\n' << flush; 
    delete[] cp; //remember to delete!! 
    //pointer to ref 
    func(cp); 
    cout << "Index 0: " << cp[0] << '\n' << flush; 
    delete[] cp; 
    return 0; 
} 

instatiating fonksiyonunun kapsamı dışına bellek kaynaklarının bertaraf RAII itaatsizlik.