Melewati referensi ke petunjuk dalam C ++


130

Sejauh yang saya tahu, tidak ada alasan saya tidak diizinkan untuk memberikan referensi ke pointer di C ++. Namun, upaya saya untuk melakukannya gagal, dan saya tidak tahu mengapa.

Inilah yang saya lakukan:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

Dan saya mendapatkan kesalahan ini:

tidak dapat mengonversi parameter 1 dari 'std :: string *' ke 'std :: string * &'

Jawaban:


126

Fungsi Anda mengharapkan referensi ke penunjuk string aktual dalam lingkup panggilan, bukan penunjuk string anonim. Jadi:

string s;
string* _s = &s;
myfunc(_s);

harus mengkompilasi dengan baik.

Namun, ini hanya berguna jika Anda ingin memodifikasi pointer yang Anda berikan ke fungsi. Jika Anda bermaksud untuk memodifikasi string itu sendiri, Anda harus menggunakan referensi ke string seperti yang disarankan Sake. Dengan mengingat hal itu harus lebih jelas mengapa kompiler mengeluh tentang kode asli Anda. Dalam kode Anda, pointer dibuat 'on the fly', mengubah pointer itu tidak akan memiliki konsekuensi dan itu bukan yang dimaksudkan. Ide referensi (vs pointer) adalah referensi selalu menunjuk ke objek yang sebenarnya.


86

Masalahnya adalah bahwa Anda mencoba untuk mengikat sementara ke referensi, yang tidak diizinkan C ++ kecuali referensi tersebut const.

Jadi, Anda dapat melakukan salah satu dari yang berikut ini:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}


void myfunc2(string* const& val)
{
    // Do stuff to the string pointer
}

int main()
// sometime later 
{
    // ...
    string s;
    string* ps = &s;

    myfunc( ps);   // OK because ps is not a temporary
    myfunc2( &s);  // OK because the parameter is a const&
    // ...

    return 0;
}

Ini sangat instruktif untuk menulis jenis seperti yang dilakukan Burr dalam contoh No.2 - string* const& valalih - alih persamaan yang kurang dapat dibaca seperti misalnya const string* &val. Untuk mata saya ini jelas merupakan referensi const , ke pointer, ke string. Saya pribadi lebih suka menulis T const&daripada const T&dalam deklarasi untuk mendapatkan klarifikasi yang tepat ini.
fish2000

1
Nit pick (bukan kritik): Bagi saya, frasa bind a temporary to the referenceini lebih jelas dalam jawaban ini daripada @Chris 'as reference to an actual string pointer in the calling scope, not an anonymous string pointer. Bagaimanapun, keduanya kemungkinan benar dari sudut pandang saya.
kevinarpe

1
@ fish2000 Tidak hanya itu, const string*&dan string* const&sebenarnya jenis yang berbeda. Yang pertama adalah constreferensi ke a const string*, sedangkan yang kedua adalah constreferensi ke a string*.
Justin Time - Kembalikan Monica

@ fish2000 waspadalah terhadap "prefering" T const&to const T&- seperti yang ditunjukkan oleh @Justin Time, mereka adalah tipe yang berbeda. Ini mungkin tidak memiliki konsekuensi kadang-kadang, tetapi dalam situasi lain akan benar-benar penting untuk memilih satu atau yang lain, seperti lebih memilih intuntuk double.
omatai

3
@ fish2000 - yang satu mengatakan "ini referensi yang bisa Anda ubah ke sesuatu yang tidak bisa Anda ubah" sementara yang lain mengatakan "ini referensi yang tidak bisa Anda ubah ke sesuatu yang bisa Anda ubah". Dalam contoh yang diberikan ini, Anda tidak bisa menukar keduanya.
omatai

10

Ubah ke:

  std::string s;
  std::string* pS = &s;
  myfunc(pS);

EDIT:

Ini disebut ref-to-pointerdan Anda tidak dapat memberikan alamat sementara sebagai referensi untuk fungsi. (kecuali jika itu const reference).

Meskipun, saya telah menunjukkan std::string* pS = &s;(pointer ke variabel lokal), penggunaannya yang khas adalah: ketika Anda ingin callee untuk mengubah pointer itu sendiri, bukan objek yang ditunjuknya. Misalnya, fungsi yang mengalokasikan memori dan menetapkan alamat blok memori yang dialokasikan untuk argumennya harus mengambil referensi ke pointer, atau pointer ke pointer:

void myfunc(string*& val)
{
//val is valid even after function call
   val = new std::string("Test");

}

5

&s menghasilkan penunjuk sementara ke string dan Anda tidak dapat membuat referensi ke objek sementara.


4
Ini tidak sepenuhnya benar - Anda dapat membuat referensi ke const sementara
1800 INFORMASI

3

Mencoba:

void myfunc(string& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(s);
    // ...
}

atau

void myfunc(string* val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

Untuk apa yang saya lakukan, saya perlu alamat pointer serta pointer itu sendiri. Saya tidak ingin meneruskan pointer dengan nilai.
Alex

Masih belum mengerti apa yang Anda coba capai. Anda tidak dapat memiliki "alamat penunjuk" dari "string s", hanya karena "string s" bukan sebuah penunjuk.
Sake

@Alex: Saya menganggap Anda perlu mendeteksi apakah string persis sama dengan yang Anda simpan dan bukan hanya apakah isinya sama. Jika demikian, perhatikan bahwa Anda dapat menggunakan alamat-operator untuk referensi dan itu akan memberi Anda alamat objek yang direferensikan: void f (std :: string const & s) {std :: string const * p = & s; }
David Rodríguez - dribeas

3

EDIT: Saya mencoba beberapa, dan menemukan sesuatu yang sedikit lebih halus dari yang saya kira. Inilah yang sekarang saya pikirkan adalah jawaban yang akurat.

&sbukan lvalue sehingga Anda tidak dapat membuat referensi untuk itu kecuali jika jenis rujukannya adalah const. Jadi misalnya, Anda tidak dapat melakukannya

string * &r = &s;

tapi kamu bisa melakukannya

string * const &r = &s;

Jika Anda meletakkan deklarasi serupa di header fungsi, itu akan berfungsi.

void myfunc(string * const &a) { ... }

Ada masalah lain, yaitu, sementara. Aturannya adalah Anda hanya bisa mendapatkan referensi sementara jika itu const. Jadi dalam hal ini orang mungkin berpendapat bahwa & s bersifat sementara, dan karenanya harus dinyatakan constdalam prototipe fungsi. Dari sudut pandang praktis, tidak ada bedanya dalam kasus ini. (Ini baik nilai atau sementara. Either way, aturan yang sama berlaku.) Namun, secara tegas, saya pikir itu bukan sementara tapi nilai. Saya bertanya-tanya apakah ada cara untuk membedakan keduanya. (Mungkin hanya didefinisikan bahwa semua temporari adalah nilai, dan semua bukan-nilai adalah temporal. Saya bukan ahli dalam standar.)

Yang sedang berkata, masalah Anda mungkin pada tingkat yang lebih tinggi. Mengapa Anda ingin referensi ke alamat s? Jika Anda ingin referensi ke pointer s, Anda perlu mendefinisikan pointer seperti di

string *p = &s;
myfunc(p);

Jika Anda ingin referensi satau penunjuk s, lakukan hal langsung.


1

Saya baru saja menggunakan referensi ke pointer untuk membuat semua pointer di pohon biner yang dihapus kecuali root safe. Untuk membuat pointer aman, kita hanya perlu mengaturnya ke 0. Saya tidak bisa membuat fungsi yang menghapus pohon (hanya menyimpan root) untuk menerima ref ke pointer karena saya menggunakan root (pointer ini) sebagai yang pertama masukan untuk melintasi kiri dan kanan.

void BinTree::safe_tree(BinTree * &vertex ) {
    if ( vertex!=0 ) {  // base case
        safe_tree(vertex->left);    // left subtree.
            safe_tree(vertex->right);   //  right subtree.
          // delete vertex;  // using this delete causes an error, since they were deleted on the fly using inorder_LVR. If inorder_LVR does not perform delete to the nodes, then, use delete vertex;
        vertex=0;  // making a safe pointer
    }
} // end in

Intinya, referensi ke pointer tidak valid ketika parameter formal adalah pointer (ini).


1

Selamat datang di C ++ 11 dan nilai referensi:

#include <cassert>
#include <string>

using std::string;

void myfunc(string*&& val)
{
    assert(&val);
    assert(val);
    assert(val->c_str());
    // Do stuff to the string pointer
}

// sometime later 
int main () {
    // ...
    string s;
    myfunc(&s);
    // ...
}

Sekarang Anda memiliki akses ke nilai pointer (disebut oleh val), yang merupakan alamat string.

Anda dapat memodifikasi pointer, dan tidak ada yang peduli. Itu adalah salah satu aspek dari apa nilai di tempat pertama.

Hati-hati: Nilai pointer hanya valid hingga myfunc()kembali. Akhirnya, ini hanya sementara.


-1

Saya tahu bahwa itu mungkin untuk melewati referensi pointer, saya melakukannya minggu lalu, tetapi saya tidak ingat apa sintaksinya, karena kode Anda terlihat benar di otak saya saat ini. Namun opsi lain adalah menggunakan pointer dari pointer:

Myfunc(String** s)

-8

myfunc ("string * & val") ini sendiri tidak masuk akal. "string * & val" menyiratkan "string val", * dan & membatalkan satu sama lain. Akhirnya kita tidak bisa memasukkan variabel string ke suatu fungsi ("string val"). Hanya tipe data dasar yang dapat diteruskan ke suatu fungsi, untuk tipe data lainnya harus lulus sebagai penunjuk atau referensi. Anda dapat memiliki string & val atau string * val ke suatu fungsi.


4
Salah di semua level. Harap segarkan sintaks deklarasi var Anda.
Ari
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.