Hangi koşullarda bu tür bir kodu c ++ 'da kullanmak istersiniz?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
Hangi koşullarda bu tür bir kodu c ++ 'da kullanmak istersiniz?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
Yanıtlar:
İmlecin işaret ettiği nesne yerine işaretçiyi değiştirmeye ihtiyacınız varsa, bir işaretçiyi referans olarak geçirmek isteyebilirsiniz.
Bu, neden çift işaretçilerin kullanıldığına benzer; bir işaretçiye başvuru kullanmak, işaretçi kullanmaktan biraz daha güvenlidir.
delete
bırakamıyor veya bellekteki başka bir yere yeniden bağlayamıyor mu? Yoksa yanlış mı anladım?
[]
operatörü aşırı yükleyeceksiniz. Bunun olası (ve aslında doğal) bir imzası olabilir const T &operator[](size_t index) const
. Ama sen de yapabilirdin T &operator[](size_t index)
. İkisine de aynı anda sahip olabilirsiniz. İkincisi, buna benzer şeyler yapmanıza izin verirdi myArray[jj] = 42
. Aynı zamanda, verilerinize bir işaretçi sağlamazsınız, böylece arayan kişi hafızayı karıştıramaz (örneğin, yanlışlıkla silebilirsiniz).
C ++ programcılarının% 50'si, bir silme işleminden sonra işaretçilerini boş olarak ayarlamak ister:
template<typename T>
void moronic_delete(T*& p)
{
delete p;
p = nullptr;
}
Referans olmadan, arayanı etkilemeden sadece işaretçinin yerel bir kopyasını değiştirmiş olursunuz.
paranoid_delete
, ancak Puppy olarak yeniden adlandırılırdı moronic_delete
. Muhtemelen diğer% 50'ye aittir;) Her neyse, kısa cevap şudur: Null after ayarlarının delete
neredeyse hiçbir zaman yararlı olmadığı (çünkü yine de kapsam dışına çıkmaları gerekir) ve çoğu zaman "ücretsiz sonra kullan" hatalarının tespitini engeller.
delete
genel olarak aptalca olduğunu düşünüyor . Yavru köpek, biraz googling yaptım, silme işleminin neden tamamen işe yaramaz olduğunu anlayamıyorum (belki de ben de berbat bir Google çalışanıyım;)). Biraz daha açıklayabilir misin veya bir bağlantı verebilir misin?
David'in cevabı doğru, ancak yine de biraz soyutsa, işte iki örnek:
Bellek sorunlarını daha önce yakalamak için tüm serbest işaretçileri sıfırlamak isteyebilirsiniz. Yapacağınız C tarzı:
void freeAndZero(void** ptr)
{
free(*ptr);
*ptr = 0;
}
void* ptr = malloc(...);
...
freeAndZero(&ptr);
C ++ 'da aynısını yapmak için şunları yapabilirsiniz:
template<class T> void freeAndZero(T* &ptr)
{
delete ptr;
ptr = 0;
}
int* ptr = new int;
...
freeAndZero(ptr);
Bağlantılı listelerle uğraşırken - genellikle bir sonraki düğüme işaretçiler olarak gösterilir:
struct Node
{
value_t value;
Node* next;
};
Bu durumda, boş listeye eklediğinizde, gelen işaretçiyi mutlaka değiştirmeniz gerekir çünkü sonuç NULL
artık işaretçi değildir . Bu, bir işlevden harici bir işaretçiyi değiştirdiğiniz bir durumdur, böylece imzasında işaretçiye bir başvuru olabilir:
void insert(Node* &list)
{
...
if(!list) list = new Node(...);
...
}
Bu soruda bir örnek var .
Geçilen bir işaretçiye bellek ayırmak ve boyutunu döndürmek için işlevler sağlamak için böyle bir kod kullanmak zorunda kaldım çünkü şirketim STL'yi kullanarak bana "nesne"
int iSizeOfArray(int* &piArray) {
piArray = new int[iNumberOfElements];
...
return iNumberOfElements;
}
Bu hoş değil, ancak gösterici referansla geçmelidir (veya çift işaretçi kullanın). Değilse, değer tarafından geçirilirse, göstericinin yerel bir kopyasına bellek ayrılır ve bu da bellek sızıntısına neden olur.
Bir örnek, bir ayrıştırıcı işlevi yazıp okumak için bir kaynak işaretçisi ilettiğinizde, işlevin bu işaretçiyi ayrıştırıcı tarafından doğru şekilde tanınan son karakterin arkasına itmesi gerekiyorsa. Bir işaretçiye referans kullanmak, işlevin konumunu güncellemek için orijinal işaretçiyi hareket ettireceğini netleştirir.
Genel olarak, bir işleve bir işaretçiyi iletmek ve orijinal işaretçiyi orijinali etkilemeden bir kopyasını taşımak yerine başka bir konuma taşımak istiyorsanız, işaretçiler için referanslar kullanırsınız .
Buna ihtiyaç duyabileceğiniz başka bir durum, stl işaretçiler koleksiyonunuz varsa ve bunları stl algoritması kullanarak değiştirmek istemenizdir. C ++ 98'de for_each örneği.
struct Storage {
typedef std::list<Object*> ObjectList;
ObjectList objects;
void change() {
typedef void (*ChangeFunctionType)(Object*&);
std::for_each<ObjectList::iterator, ChangeFunctionType>
(objects.begin(), objects.end(), &Storage::changeObject);
}
static void changeObject(Object*& item) {
delete item;
item = 0;
if (someCondition) item = new Object();
}
};
Aksi takdirde, changeObject (Nesne * öğe) imzasını kullanırsanız, orijinal değil, işaretçinin kopyasına sahip olursunuz.