Saat membaca penjelasan tentang lvalues dan rvalues ini, baris kode berikut menarik perhatian saya:
int& foo();
foo() = 42; // OK, foo() is an lvalue
Saya mencobanya di g ++, tetapi kompilernya mengatakan "referensi tidak terdefinisi ke foo ()". Jika saya menambahkan
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
Ini mengkompilasi dengan baik, tetapi menjalankannya memberikan kesalahan segmentasi . Hanya garisnya
int& foo();
dengan sendirinya mengkompilasi dan berjalan tanpa masalah.
Apa arti kode ini? Bagaimana Anda bisa menetapkan nilai ke panggilan fungsi, dan mengapa itu bukan nilai r?
c++
function
return-by-reference
Sossisos
sumber
sumber
Jawaban:
Penjelasannya mengasumsikan bahwa ada beberapa implementasi yang masuk akal
foo
yang mengembalikan referensi nilai l ke validint
.Implementasi seperti itu mungkin:
Sekarang, karena
foo
mengembalikan referensi lvalue, kita dapat menetapkan sesuatu ke nilai kembalian, seperti:Ini akan memperbarui global
a
dengan nilai42
, yang dapat kita periksa dengan mengakses variabel secara langsung atau memanggilfoo
lagi:sumber
Semua jawaban lainnya menyatakan statis di dalam fungsi. Saya pikir itu mungkin membingungkan Anda, jadi lihat ini:
Karena
highest()
mengembalikan referensi, Anda dapat menetapkan nilai padanya. Ketika ini berjalan,b
akan berubah menjadi 11. Jika Anda mengubah inisialisasi sehinggaa
, katakanlah, 8, makaa
akan berubah menjadi 11. Ini adalah beberapa kode yang mungkin benar-benar memiliki tujuan, tidak seperti contoh lainnya.sumber
Mendeklarasikan fungsi bernama foo yang mengembalikan referensi ke file
int
. Contoh yang gagal dilakukan adalah memberikan definisi fungsi yang dapat Anda kompilasi. Jika kami menggunakanSekarang kita memiliki fungsi yang mengembalikan referensi
bar
. karena bilahstatic
itu akan hidup setelah panggilan ke fungsi sehingga mengembalikan referensi ke sana aman. Sekarang jika kita melakukannyaApa yang terjadi adalah kita menetapkan 42
bar
karena kita menetapkan ke referensi dan referensi tersebut hanyalah alias untukbar
. Kalau kita panggil lagi fungsinya sepertiIni akan mencetak 42 karena kita mengaturnya di
bar
atas.sumber
int &foo();
mendeklarasikan fungsi yang dipanggilfoo()
dengan tipe returnint&
. Jika Anda memanggil fungsi ini tanpa menyediakan isi maka kemungkinan besar Anda akan mendapatkan kesalahan referensi yang tidak ditentukan.Dalam upaya kedua Anda, Anda memberikan fungsi
int foo()
. Ini memiliki tipe pengembalian yang berbeda dengan fungsi yang dideklarasikan olehint& foo();
. Jadi Anda memiliki dua deklarasi yang samafoo
yang tidak cocok, yang melanggar Aturan Satu Definisi yang menyebabkan perilaku tidak terdefinisi (tidak diperlukan diagnostik).Untuk sesuatu yang berhasil, keluarkan deklarasi fungsi lokal. Mereka dapat menyebabkan perilaku diam yang tidak terdefinisi seperti yang Anda lihat. Sebagai gantinya, gunakan hanya deklarasi fungsi di luar fungsi apa pun. Program Anda akan terlihat seperti:
sumber
int& foo();
adalah fungsi yang mengembalikan referensi keint
. Fungsi yang Anda berikan kembaliint
tanpa referensi.Anda boleh melakukannya
sumber
int & foo();
artinyafoo()
mengembalikan referensi ke variabel.Pertimbangkan kode ini:
Kode ini mencetak:
$ ./a.out k = 5
Karena
foo()
mengembalikan referensi ke variabel globalk
.Dalam kode yang direvisi, Anda mentransmisikan nilai yang dikembalikan ke referensi, yang kemudian tidak valid.
sumber
Dalam konteks itu & berarti referensi - jadi foo mengembalikan referensi ke int, bukan int.
Saya tidak yakin apakah Anda telah bekerja dengan pointer, tapi itu ide yang sama, Anda tidak benar-benar mengembalikan nilai dari fungsinya - sebagai gantinya Anda meneruskan informasi yang diperlukan untuk menemukan lokasi dalam memori di mana itu int adalah.
Jadi untuk meringkas Anda tidak menetapkan nilai ke panggilan fungsi - Anda menggunakan fungsi untuk mendapatkan referensi, lalu menetapkan nilai yang direferensikan ke nilai baru. Sangat mudah untuk berpikir bahwa semuanya terjadi sekaligus, tetapi pada kenyataannya komputer melakukan semuanya dengan urutan yang tepat.
Jika Anda bertanya-tanya - alasan Anda mendapatkan segfault adalah karena Anda mengembalikan literal numerik '2' - jadi itu adalah kesalahan tepat yang akan Anda dapatkan jika Anda mendefinisikan sebuah const int dan kemudian mencoba untuk memodifikasi nilai.
Jika Anda belum belajar tentang pointer dan memori dinamis, maka saya akan merekomendasikannya terlebih dahulu karena ada beberapa konsep yang menurut saya sulit untuk dipahami kecuali Anda mempelajarinya sekaligus.
sumber
Kode contoh di halaman yang ditautkan hanyalah deklarasi fungsi tiruan. Ini tidak dapat dikompilasi, tetapi jika Anda memiliki beberapa fungsi yang ditentukan, ini akan bekerja secara umum. Contoh tersebut berarti "Jika Anda memiliki fungsi dengan tanda tangan ini, Anda dapat menggunakannya seperti itu".
Dalam contoh Anda,
foo
jelas mengembalikan nilai l berdasarkan tanda tangan, tetapi Anda mengembalikan nilai r yang diubah menjadi nilai l. Ini jelas ditentukan untuk gagal. Anda bisa melakukan:dan akan berhasil dengan mengubah nilai x, ketika mengatakan:
sumber
Fungsi yang Anda miliki, foo (), adalah fungsi yang mengembalikan referensi ke integer.
Jadi katakanlah aslinya foo dikembalikan 5, dan kemudian, di fungsi utama Anda, Anda katakan
foo() = 10;
, lalu mencetak foo, itu akan mencetak 10 bukan 5.Saya harap itu masuk akal :)
Saya baru mengenal pemrograman juga. Sangat menarik melihat pertanyaan seperti ini yang membuat Anda berpikir! :)
sumber