Temporaries tidak dapat terikat pada referensi non-konstan. int (12) adalah sementara dalam kasus ini.
Prasoon Saurav
@PrasoonSaurav Apa yang Anda maksud dengan 12 sementara? Kurangnya konsep di sini (di pihak saya :))
Aquarius_Girl
2
Perhatikan bahwa tidak ada alasan teknis yang ketat untuk pembatasan ini. Ini akan semudah diimplementasikan untuk memungkinkan referensi yang bisa berubah untuk sementara. Melarang itu adalah keputusan desain C ++, karena konstruksi seperti itu akan menjadi desain yang buruk dengan risiko yang jauh lebih besar untuk disalahgunakan secara tidak sengaja daripada utilitas asli. (Saya hanya sekali menemukan kebutuhan yang dibuat-buat untuk hal seperti itu.)
Kerrek SB
@KerrekSB kebutuhan paling umum untuk ref mengikat untuk menilai objek mungkin adalah(ostringstream() << "x=" << x).str()
penasaran
@curiousguy: Ya, itulah isi dari link yang saya posting.
Kerrek SB
Jawaban:
133
C ++ 03 3.10 / 1 mengatakan: "Setiap ekspresi adalah nilai l atau nilai r." Penting untuk diingat bahwa lvalueness versus rvalueness adalah properti ekspresi, bukan objek.
Lvalues nama objek yang tetap ada di luar ekspresi tunggal. Sebagai contoh, obj, *ptr, ptr[index], dan ++xsemua lvalues.
Nilai R adalah nilai temporer yang menguap pada akhir ekspresi penuh tempat nilai tersebut berada ("di titik koma"). Sebagai contoh, 1729, x + y, std::string("meow"), dan x++semua rvalues.
Operator alamat mensyaratkan bahwa "operan harus menjadi nilai l". jika kita bisa mengambil alamat dari satu ekspresi, ekspresi itu adalah nilai l, jika tidak, itu adalah nilai r.
" jika kita bisa mengambil alamat dari satu ekspresi, ekspresi itu adalah nilai l, jika tidak, itu adalah nilai r. " jika hanya C ++ sesederhana itu! (tapi nuansanya tidak terlalu relevan di sini) "Nilai adalah sementara" sementara apa? benda?
penasaran
2
@curiousguyRvalues adalah sementara yang menghilang di akhir ekspresi penuh tempat mereka tinggal. Untuk hanya menjawab mengapa express int & = 12;tidak valid, standar mengatakan string literal adalah nilai l, literal lainnya adalah nilai r.
BruceAdi
@curiousguy: Ya. Rvalues adalah obyek sementara , tetapi tidak semua rvalues adalah obyek sementara; beberapa bahkan bukan objek.
Nawaz
" Misalnya, 1729, x + y, std :: string (" meow "), dan x ++ semuanya adalah nilai r. " Tetapi std::string("meow")membuat objek berjenis std::stringdan menghasilkan nilai r yang menunjukkan objek ini, 1729tidak memiliki efek samping dan menghasilkan nilai 1729 sebagai nilai r dari tipe int.
penasaran
1
@curiousguy: Pernyataan tersebut "Lvalues name objects that persist beyond a single expression."adalah pernyataan yang 100% benar. Sebaliknya, contoh Anda (const int &)1salah, karena Ini BUKAN objek "bernama".
Nawaz
53
int &z = 12;
Di sisi kanan, objek sementara tipe intdibuat dari literal integral 12, tetapi sementara tidak dapat terikat ke referensi non-const. Karena itu kesalahannya. Itu sama dengan:
int &z = int(12); //still same error
Mengapa sementara dibuat? Karena referensi harus merujuk ke objek dalam memori, dan agar objek ada, itu harus dibuat terlebih dahulu. Karena objek tidak bernama, itu adalah objek sementara . Tidak ada nama. Dari penjelasan ini, menjadi sangat jelas mengapa kasus kedua baik-baik saja.
Objek sementara dapat diikat ke referensi const, yang berarti, Anda dapat melakukan ini:
constint &z = 12; //ok
C ++ 11 dan Rvalue Reference:
Demi kelengkapan, saya ingin menambahkan bahwa C ++ 11 telah memperkenalkan rvalue-reference, yang dapat mengikat objek sementara. Jadi di C ++ 11, Anda bisa menulis ini:
int && z = 12; //C+11 only
Perhatikan bahwa ada &&pengganti &. Perhatikan juga bahwa constsudah tidak dibutuhkan lagi, padahal objek yang zdiikat merupakan objek sementara yang dibuat dari integral-literal 12.
Karena C ++ 11 telah memperkenalkan rvalue-reference , untuk int&selanjutnya disebut lvalue-reference .
@curiousguy, konsistenlah, Anda telah mengatakan "Anda harus memahami bahwa ini adalah aturan C ++. Aturan tersebut ada, dan tidak memerlukan pembenaran apa pun" (belum lagi edisi pertama). Bagaimana saya mengartikan keluhan Anda tidak memberikan apa yang menurut Anda tidak dibutuhkan?
Michael Krelin - peretas
2
@ MichaelKrelin-hacker: Secara teknis tidak, Anda tidak dapat (pernah) mengikat referensi ke nilai (atau mengkompilasi konstanta waktu), standarnya cukup eksplisit mengenai apa yang sebenarnya terjadi: Jika tidak, tipe sementara "cv1 T1" dibuat dan diinisialisasi dari ekspresi penginisialisasi menggunakan aturan untuk inisialisasi salinan non-referensi (8.5). Referensi kemudian terikat ke sementara. Artinya, sintaksis diperbolehkan, tetapi semantik tidak mengikat referensi ke konstanta, melainkan mengikatnya ke sementara yang dibuat secara tersirat.
David Rodríguez - dribeas
1
@curiousguy: Aturan bahasa adalah bagian dari desain, dan lebih sering daripada tidak, ada pembenaran mengapa bahasa itu dirancang seperti itu. Dalam kasus khusus ini, seperti di C Anda tidak diizinkan untuk mengambil alamat dari suatu nilai (tidak ada), Anda juga tidak dapat mengikat referensi. Sekarang pertimbangkan sebuah fungsi void f( vector<int> const & ), yang idiomatis melewatkan vektor yang tidak akan dimodifikasi. Masalahnya sekarang adalah itu f( vector<int>(5) )tidak benar, dan pengguna harus memberikan kelebihan beban berbeda void f( vector<int> v ) { f(v); }yang sepele.
David Rodríguez - dribeas
1
... sekarang karena itu akan menyakitkan bagi pengguna bahasa, perancang memutuskan bahwa kompilator akan melakukan operasi yang setara untuk Anda, dalam panggilan f( vector<int>(5) ), kompilator membuat sementara dan kemudian mengikat referensi ke sementara itu, dan serupa jika ada konversi implisit dari 5langsung. Hal ini memungkinkan kompiler untuk menghasilkan satu tanda tangan untuk fungsi tersebut dan memungkinkan implementasi fungsi oleh pengguna tunggal. Sejak saat itu, perilaku serupa didefinisikan untuk sisa penggunaan referensi konstan untuk konsistensi.
David Rodríguez - dribeas
1
@ MichaelKrelin-hacker: referensi adalah alias ke objek, dan nilai bukan objek. Bergantung pada konteksnya, referensi bisa saja alias kompilator menghapus referensi dan hanya menggunakan pengenal untuk mengartikan apa pun yang dimaksud objek aslinya ( T const & r = *ptr;, penggunaan nanti rdalam fungsi dapat diganti *ptr, dan rtidak perlu ada saat runtime) atau mungkin harus diimplementasikan dengan menyimpan alamat objek yang alias (pertimbangkan untuk menyimpan referensi sebagai anggota objek) - yang diimplementasikan sebagai penunjuk autodereferensi.
David Rodríguez - dribeas
4
Pengikatan referensi non-const dan const mengikuti aturan yang berbeda
Ini adalah aturan bahasa C ++:
ekspresi yang terdiri dari angka literal ( 12) adalah "nilai r"
tidak diizinkan untuk membuat referensi non-const dengan rvalue: int &ri = 12;berbentuk buruk
diperbolehkan untuk membuat referensi const dengan rvalue: dalam kasus ini, objek tanpa nama dibuat oleh kompilator; objek ini akan tetap ada selama referensi itu sendiri ada.
Anda harus memahami bahwa ini adalah aturan C ++. Mereka memang begitu.
Sangat mudah untuk menemukan bahasa yang berbeda, katakanlah C ++ ', dengan aturan yang sedikit berbeda. Dalam C ++ ', akan diizinkan untuk membuat referensi non-const dengan rvalue. Tidak ada yang tidak konsisten atau tidak mungkin di sini.
Tetapi itu akan memungkinkan beberapa kode berisiko di mana pemrogram mungkin tidak mendapatkan apa yang dia inginkan, dan perancang C ++ dengan tepat memutuskan untuk menghindari risiko itu.
Referensi adalah "petunjuk tersembunyi" (bukan nol) ke hal-hal yang dapat berubah (lvalues). Anda tidak dapat mendefinisikannya menjadi sebuah konstanta. Ini harus menjadi hal "variabel".
EDIT ::
Saya sedang memikirkan
int &x = y;
hampir setara dengan
int* __px = &y;
#define x (*__px)
where __pxis a fresh name, and the #define xworks only inside the block of the declaration of xreference.
(ostringstream() << "x=" << x).str()
Jawaban:
C ++ 03 3.10 / 1 mengatakan: "Setiap ekspresi adalah nilai l atau nilai r." Penting untuk diingat bahwa lvalueness versus rvalueness adalah properti ekspresi, bukan objek.
Lvalues nama objek yang tetap ada di luar ekspresi tunggal. Sebagai contoh,
obj
,*ptr
,ptr[index]
, dan++x
semua lvalues.Nilai R adalah nilai temporer yang menguap pada akhir ekspresi penuh tempat nilai tersebut berada ("di titik koma"). Sebagai contoh,
1729
,x + y
,std::string("meow")
, danx++
semua rvalues.Operator alamat mensyaratkan bahwa "operan harus menjadi nilai l". jika kita bisa mengambil alamat dari satu ekspresi, ekspresi itu adalah nilai l, jika tidak, itu adalah nilai r.
&obj; // valid &12; //invalid
sumber
int & = 12;
tidak valid, standar mengatakan string literal adalah nilai l, literal lainnya adalah nilai r.std::string("meow")
membuat objek berjenisstd::string
dan menghasilkan nilai r yang menunjukkan objek ini,1729
tidak memiliki efek samping dan menghasilkan nilai 1729 sebagai nilai r dari tipeint
."Lvalues name objects that persist beyond a single expression."
adalah pernyataan yang 100% benar. Sebaliknya, contoh Anda(const int &)1
salah, karena Ini BUKAN objek "bernama".int &z = 12;
Di sisi kanan, objek sementara tipe
int
dibuat dari literal integral12
, tetapi sementara tidak dapat terikat ke referensi non-const. Karena itu kesalahannya. Itu sama dengan:int &z = int(12); //still same error
Mengapa sementara dibuat? Karena referensi harus merujuk ke objek dalam memori, dan agar objek ada, itu harus dibuat terlebih dahulu. Karena objek tidak bernama, itu adalah objek sementara . Tidak ada nama. Dari penjelasan ini, menjadi sangat jelas mengapa kasus kedua baik-baik saja.
Objek sementara dapat diikat ke referensi const, yang berarti, Anda dapat melakukan ini:
const int &z = 12; //ok
C ++ 11 dan Rvalue Reference:
Demi kelengkapan, saya ingin menambahkan bahwa C ++ 11 telah memperkenalkan rvalue-reference, yang dapat mengikat objek sementara. Jadi di C ++ 11, Anda bisa menulis ini:
int && z = 12; //C+11 only
Perhatikan bahwa ada
&&
pengganti&
. Perhatikan juga bahwaconst
sudah tidak dibutuhkan lagi, padahal objek yangz
diikat merupakan objek sementara yang dibuat dari integral-literal12
.Karena C ++ 11 telah memperkenalkan rvalue-reference , untuk
int&
selanjutnya disebut lvalue-reference .sumber
12
adalah konstanta waktu kompilasi yang tidak dapat diubah tidak seperti data yang dirujukint&
. Yang bisa Anda lakukan adalahconst int& z = 12;
sumber
void f( vector<int> const & )
, yang idiomatis melewatkan vektor yang tidak akan dimodifikasi. Masalahnya sekarang adalah ituf( vector<int>(5) )
tidak benar, dan pengguna harus memberikan kelebihan beban berbedavoid f( vector<int> v ) { f(v); }
yang sepele.f( vector<int>(5) )
, kompilator membuat sementara dan kemudian mengikat referensi ke sementara itu, dan serupa jika ada konversi implisit dari5
langsung. Hal ini memungkinkan kompiler untuk menghasilkan satu tanda tangan untuk fungsi tersebut dan memungkinkan implementasi fungsi oleh pengguna tunggal. Sejak saat itu, perilaku serupa didefinisikan untuk sisa penggunaan referensi konstan untuk konsistensi.T const & r = *ptr;
, penggunaan nantir
dalam fungsi dapat diganti*ptr
, danr
tidak perlu ada saat runtime) atau mungkin harus diimplementasikan dengan menyimpan alamat objek yang alias (pertimbangkan untuk menyimpan referensi sebagai anggota objek) - yang diimplementasikan sebagai penunjuk autodereferensi.Pengikatan referensi non-const dan const mengikuti aturan yang berbeda
Ini adalah aturan bahasa C ++:
12
) adalah "nilai r"int &ri = 12;
berbentuk burukAnda harus memahami bahwa ini adalah aturan C ++. Mereka memang begitu.
Sangat mudah untuk menemukan bahasa yang berbeda, katakanlah C ++ ', dengan aturan yang sedikit berbeda. Dalam C ++ ', akan diizinkan untuk membuat referensi non-const dengan rvalue. Tidak ada yang tidak konsisten atau tidak mungkin di sini.
Tetapi itu akan memungkinkan beberapa kode berisiko di mana pemrogram mungkin tidak mendapatkan apa yang dia inginkan, dan perancang C ++ dengan tepat memutuskan untuk menghindari risiko itu.
sumber
Referensi adalah "petunjuk tersembunyi" (bukan nol) ke hal-hal yang dapat berubah (lvalues). Anda tidak dapat mendefinisikannya menjadi sebuah konstanta. Ini harus menjadi hal "variabel".
EDIT ::
Saya sedang memikirkan
int &x = y;
hampir setara dengan
int* __px = &y; #define x (*__px)
where
__px
is a fresh name, and the#define x
works only inside the block of the declaration ofx
reference.sumber
const
:)const