Dalam keadaan apa Anda ingin menggunakan kode seperti ini di c ++?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
Dalam keadaan apa Anda ingin menggunakan kode seperti ini di c ++?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
Jawaban:
Anda ingin meneruskan pointer dengan referensi jika Anda memiliki kebutuhan untuk memodifikasi pointer daripada objek yang ditunjuk pointer.
Ini mirip dengan mengapa penunjuk ganda digunakan; menggunakan referensi ke pointer sedikit lebih aman daripada menggunakan pointer.
delete
atau memasang kembali pointer itu ke tempat lain di memori? Atau apakah saya salah?
[]
operator. Salah satu tanda tangan yang mungkin (dan sebenarnya alami) untuk ini adalah const T &operator[](size_t index) const
. Tapi Anda juga bisa melakukannya T &operator[](size_t index)
. Anda bisa mendapatkan keduanya pada saat bersamaan. Yang terakhir akan memungkinkan Anda melakukan hal-hal seperti myArray[jj] = 42
. Pada saat yang sama, Anda tidak memberikan penunjuk ke data Anda, sehingga pemanggil tidak dapat mengacaukan memori (misalnya menghapusnya secara tidak sengaja).
50% programmer C ++ suka mengatur pointer mereka ke null setelah menghapus:
template<typename T>
void moronic_delete(T*& p)
{
delete p;
p = nullptr;
}
Tanpa referensi, Anda hanya akan mengubah salinan lokal penunjuk, tidak memengaruhi pemanggil.
paranoid_delete
, tapi Puppy menamainya moronic_delete
. Dia mungkin termasuk 50% lainnya;) Bagaimanapun, jawaban singkatnya adalah bahwa pengaturan menunjuk ke nol setelah delete
hampir tidak pernah berguna (karena mereka harus keluar dari ruang lingkup, bagaimanapun) dan sering menghambat deteksi bug "gunakan setelah gratis".
delete
dianggap bodoh secara umum. Anak anjing, saya melakukan beberapa googling, saya tidak mengerti mengapa menghapus sama sekali tidak berguna (mungkin saya juga googler yang buruk;)). Bisakah Anda menjelaskan lebih banyak atau memberikan tautan?
Jawaban David benar, tetapi jika masih sedikit abstrak, berikut dua contohnya:
Anda mungkin ingin menghapus semua petunjuk yang dibebaskan untuk mengetahui masalah memori sebelumnya. Gaya C yang akan Anda lakukan:
void freeAndZero(void** ptr)
{
free(*ptr);
*ptr = 0;
}
void* ptr = malloc(...);
...
freeAndZero(&ptr);
Di C ++ untuk melakukan hal yang sama, Anda dapat melakukan:
template<class T> void freeAndZero(T* &ptr)
{
delete ptr;
ptr = 0;
}
int* ptr = new int;
...
freeAndZero(ptr);
Saat berurusan dengan daftar tertaut - sering kali hanya direpresentasikan sebagai petunjuk ke node berikutnya:
struct Node
{
value_t value;
Node* next;
};
Dalam kasus ini, ketika Anda menyisipkan ke daftar kosong Anda harus mengubah penunjuk yang masuk karena hasilnya bukan NULL
penunjuk lagi. Ini adalah kasus di mana Anda memodifikasi penunjuk eksternal dari suatu fungsi, sehingga akan memiliki referensi ke penunjuk dalam tanda tangannya:
void insert(Node* &list)
{
...
if(!list) list = new Node(...);
...
}
Ada contoh dalam pertanyaan ini .
Saya harus menggunakan kode seperti ini untuk menyediakan fungsi untuk mengalokasikan memori ke pointer yang dikirimkan dan mengembalikan ukurannya karena "objek" perusahaan saya menggunakan STL
int iSizeOfArray(int* &piArray) {
piArray = new int[iNumberOfElements];
...
return iNumberOfElements;
}
Ini tidak bagus, tetapi penunjuk harus diteruskan dengan referensi (atau gunakan penunjuk ganda). Jika tidak, memori dialokasikan ke salinan lokal penunjuk jika diteruskan oleh nilai yang mengakibatkan kebocoran memori.
Salah satu contohnya adalah saat Anda menulis fungsi parser dan meneruskannya ke penunjuk sumber untuk dibaca, jika fungsi tersebut seharusnya mendorong penunjuk tersebut ke depan di belakang karakter terakhir yang telah dikenali dengan benar oleh parser. Menggunakan referensi ke sebuah pointer membuatnya jelas kemudian bahwa fungsi tersebut akan memindahkan pointer asli untuk memperbarui posisinya.
Secara umum, Anda menggunakan referensi ke pointer jika Anda ingin meneruskan pointer ke suatu fungsi dan membiarkannya memindahkan pointer asli ke posisi lain daripada hanya memindahkan salinannya tanpa mempengaruhi aslinya.
Situasi lain ketika Anda mungkin memerlukan ini adalah jika Anda memiliki kumpulan pointer stl dan ingin mengubahnya menggunakan algoritma stl. Contoh for_each di c ++ 98.
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();
}
};
Sebaliknya, jika Anda menggunakan tanda tangan changeObject (Object * item), Anda memiliki salinan pointer, bukan yang asli.