C ++

Kategori Taksonomi Ungkapan dalam C ++

Kategori Taksonomi Ungkapan dalam C ++

Pengiraan adalah jenis pengiraan yang mengikuti algoritma yang ditentukan dengan baik. Ungkapan adalah urutan operator dan operan yang menentukan pengiraan. Dengan kata lain, ungkapan adalah pengecam atau literal, atau urutan keduanya, yang disatukan oleh operator.Dalam pengaturcaraan, ekspresi dapat menghasilkan nilai dan / atau menyebabkan terjadinya sesuatu. Apabila menghasilkan nilai, ungkapan adalah nilai glvalue, rvalue, lvalue, xvalue, atau prvalue. Setiap kategori ini adalah satu set ungkapan. Setiap set mempunyai definisi dan situasi tertentu di mana maknanya berlaku, membezakannya dari set lain. Setiap set dipanggil kategori nilai.

Nota: Nilai atau harfiah masih merupakan ungkapan, jadi istilah ini mengklasifikasikan ungkapan dan bukan nilai sebenarnya.

glvalue dan rvalue adalah dua subset dari ungkapan set besar. glvalue wujud dalam dua subset selanjutnya: lvalue dan xvalue. rvalue, subset lain untuk ekspresi, juga terdapat dalam dua subset selanjutnya: xvalue dan prvalue. Jadi, xvalue adalah subset dari kedua nilai glvalue dan rvalue: iaitu, xvalue adalah persimpangan kedua-dua nilai dan nilai. Gambar rajah taksonomi berikut, diambil dari spesifikasi C ++, menggambarkan hubungan semua set:

prvalue, xvalue, dan lvalue adalah nilai kategori utama. glvalue adalah penyatuan nilai dan nilai x, sementara nilai adalah persatuan nilai dan nilai x.

Anda memerlukan pengetahuan asas dalam C ++ untuk memahami artikel ini; anda juga memerlukan pengetahuan mengenai Skop di C++.

Kandungan Artikel

Asas

Untuk benar-benar memahami taksonomi kategori ekspresi, anda perlu mengingat atau mengetahui ciri asas berikut terlebih dahulu: lokasi dan objek, penyimpanan dan sumber, inisialisasi, pengenal dan rujukan, rujukan nilai dan nilai, penunjuk, kedai percuma, dan penggunaan semula sumber.

Lokasi dan Objek

Pertimbangkan pernyataan berikut:

int ident;

Ini adalah deklarasi yang mengenal pasti lokasi dalam ingatan. Lokasi adalah sekumpulan byte berturut-turut dalam memori. Lokasi boleh terdiri daripada satu bait, dua bait, empat bait, enam puluh empat bait, dll. Lokasi bagi bilangan bulat untuk mesin 32bit adalah empat bait. Juga, lokasi dapat dikenal pasti oleh pengecam.

Dalam deklarasi di atas, lokasi tersebut tidak mempunyai kandungan. Ini bermaksud bahawa ia tidak mempunyai nilai, kerana isinya adalah nilai. Jadi, pengecam mengenal pasti lokasi (ruang berterusan kecil). Apabila lokasi diberi kandungan tertentu, pengenal kemudian mengenal pasti lokasi dan kandungannya; iaitu, pengecam kemudian mengenal pasti lokasi dan nilai.

Pertimbangkan pernyataan berikut:

int ident1 = 5;
int ident2 = 100;

Setiap pernyataan ini adalah deklarasi dan definisi. Pengecam pertama mempunyai nilai (kandungan) 5, dan pengecam kedua mempunyai nilai 100. Dalam mesin 32bit, setiap lokasi ini panjangnya empat bait. Pengecam pertama mengenal pasti lokasi dan nilai. Pengecam kedua juga mengenal pasti kedua-duanya.

Objek adalah kawasan penyimpanan memori yang dinamakan. Jadi, objek sama ada lokasi tanpa nilai atau lokasi dengan nilai.

Penyimpanan dan Sumber Objek

Lokasi untuk objek juga disebut penyimpanan atau sumber objek.

Permulaan

Pertimbangkan segmen kod berikut:

int ident;
ident = 8;

Baris pertama menyatakan pengecam. Deklarasi ini menyediakan lokasi (penyimpanan atau sumber) untuk objek integer, mengenal pasti dengan nama, ident. Baris seterusnya meletakkan nilai 8 (dalam bit) ke lokasi yang dikenal pasti oleh ident. Penetapan nilai ini adalah inisialisasi.

Pernyataan berikut menentukan vektor dengan kandungan, 1, 2, 3, 4, 5, yang dikenal pasti oleh vtr:

std :: vektor vtr 1, 2, 3, 4, 5;

Di sini, inisialisasi dengan 1, 2, 3, 4, 5 dilakukan dalam pernyataan definisi yang sama (deklarasi). Pengendali tugasan tidak digunakan. Pernyataan berikut menentukan array dengan kandungan 1, 2, 3, 4, 5:

int arr [] = 1, 2, 3, 4, 5;

Kali ini, operator penugasan telah digunakan untuk inisialisasi.

Pengenal dan Rujukan

Pertimbangkan segmen kod berikut:

int ident = 4;
int & ref1 = ident;
int & ref2 = ident;
cout<< ident <<"<< ref1 <<"<< ref2 << '\n';

Keluarannya adalah:

4 4 4

ident adalah pengecam, sementara ref1 dan ref2 adalah rujukan; mereka merujuk lokasi yang sama. Rujukan adalah sinonim untuk pengecam. Secara konvensional, ref1 dan ref2 adalah nama yang berbeza dari satu objek, sementara ident adalah pengenal objek yang sama. Namun, ident masih boleh disebut nama objek, yang bermaksud, ident, ref1, dan ref2 menamakan lokasi yang sama.

Perbezaan utama antara pengenal dan rujukan adalah bahawa, ketika diteruskan sebagai argumen ke fungsi, jika diteruskan oleh pengenal, salinan dibuat untuk pengenal dalam fungsi, sementara jika diteruskan dengan rujukan, lokasi yang sama digunakan dalam fungsi. Jadi, melewati pengecam berakhir dengan dua lokasi, sementara melewati dengan rujukan berakhir dengan satu lokasi yang sama.

lvalue Rujukan dan rvalue Rujukan

Cara biasa untuk membuat rujukan adalah seperti berikut:

int ident;
ident = 4;
int & ref = ident;

Storan (sumber) terletak dan dikenal pasti terlebih dahulu (dengan nama seperti ident), dan kemudian rujukan (dengan nama seperti ref) dibuat. Ketika menyampaikan sebagai argumen ke fungsi, salinan pengenal akan dibuat dalam fungsi, sementara untuk referensi, lokasi asli akan digunakan (disebut) dalam fungsi.

Hari ini, mungkin hanya mempunyai rujukan tanpa mengenalinya. Ini bermaksud mungkin membuat rujukan terlebih dahulu tanpa mempunyai pengecam lokasi. Ini menggunakan &&, seperti yang ditunjukkan dalam pernyataan berikut:

int && ref = 4;

Di sini, tidak ada pengenalan sebelumnya. Untuk mengakses nilai objek, gunakan ref seperti yang anda gunakan ident di atas.

Dengan pernyataan &&, tidak ada kemungkinan menyampaikan argumen ke fungsi oleh pengenal. Satu-satunya pilihan adalah melalui rujukan. Dalam kes ini, hanya ada satu lokasi yang digunakan dalam fungsi dan bukan lokasi kedua yang disalin seperti pengenal.

Deklarasi rujukan dengan & dipanggil rujukan nilai. Deklarasi rujukan dengan && disebut rvalue rujukan, yang juga merupakan rujukan prvalue (lihat di bawah).

Penunjuk

Pertimbangkan kod berikut:

int ptdInt = 5;
int * ptrInt;
ptrInt = &ptdInt;
cout<< *ptrInt <<'\n';

Keluarannya adalah 5.

Di sini, ptdInt adalah pengecam seperti identiti di atas. Terdapat dua objek (lokasi) di sini dan bukannya satu: objek runcing, ptdInt dikenali oleh ptdInt, dan objek penunjuk, ptrInt dikenal pasti oleh ptrInt. & ptdInt mengembalikan alamat objek runcing dan meletakkannya sebagai nilai dalam objek penunjuk ptrInt. Untuk mengembalikan (memperoleh) nilai objek runcing, gunakan pengenal untuk objek penunjuk, seperti dalam "* ptrInt".

Nota: ptdInt adalah pengecam dan bukan rujukan, sementara nama, rujukan, yang disebutkan sebelumnya, adalah rujukan.

Baris kedua dan ketiga dalam kod di atas dapat dikurangkan menjadi satu baris, menuju ke kod berikut:

int ptdInt = 5;
int * ptrInt = &ptdInt;
cout<< *ptrInt <<'\n';

Nota: Apabila penunjuk ditingkatkan, ia menunjuk ke lokasi seterusnya, yang bukan penambahan nilai 1. Apabila penunjuk dikurangkan, ia menunjukkan lokasi sebelumnya, yang bukan merupakan pengurangan nilai 1.

Kedai Percuma

Sistem operasi memperuntukkan memori untuk setiap program yang sedang berjalan. Memori yang tidak diperuntukkan untuk sebarang program dikenali sebagai kedai percuma. Ungkapan yang mengembalikan lokasi untuk bilangan bulat dari kedai percuma adalah:

int baru

Ini mengembalikan lokasi untuk bilangan bulat yang tidak dikenali. Kod berikut menggambarkan cara menggunakan penunjuk dengan kedai percuma:

int * ptrInt = int baru;
* ptrInt = 12;
cout<< *ptrInt  <<'\n';

Keluarannya adalah 12.

Untuk menghancurkan objek, gunakan ungkapan hapus seperti berikut:

padamkan ptrInt;

Argumen untuk menghapus ungkapan adalah penunjuk. Kod berikut menggambarkan penggunaannya:

int * ptrInt = int baru;
* ptrInt = 12;
padamkan ptrInt;
cout<< *ptrInt <<'\n';

Keluarannya adalah 0, dan bukan seperti batal atau tidak ditentukan. delete menggantikan nilai untuk lokasi dengan nilai lalai dari jenis lokasi tertentu, lalu membenarkan lokasi tersebut untuk digunakan kembali. Nilai lalai untuk lokasi int adalah 0.

Menggunakan semula Sumber

Dalam taksonomi kategori ekspresi, menggunakan kembali sumber adalah sama dengan menggunakan kembali lokasi atau penyimpanan untuk objek. Kod berikut menggambarkan bagaimana lokasi dari kedai percuma dapat digunakan semula:

int * ptrInt = int baru;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
padamkan ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Keluarannya adalah:

12
0
24

Nilai 12 mula-mula diberikan ke lokasi yang tidak dikenali. Kemudian kandungan lokasi dihapus (secara teori objek dihapus). Nilai 24 ditugaskan semula ke lokasi yang sama.

Program berikut menunjukkan bagaimana rujukan bilangan bulat yang dikembalikan oleh fungsi digunakan semula:

#sertakan
menggunakan ruang nama std;
int & fn ()

int i = 5;
int & j = i;
pulangan j;

int utama ()

int & myInt = fn ();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
pulangan 0;

Keluarannya adalah:

5
17

Objek seperti i, dinyatakan dalam ruang lingkup tempatan (fungsi fungsi), tidak ada lagi di akhir skop tempatan. Walau bagaimanapun, fungsi fn () di atas, mengembalikan rujukan i. Melalui rujukan yang dikembalikan ini, nama, myInt dalam fungsi utama (), menggunakan semula lokasi yang dikenalpasti oleh i untuk nilai 17.

nilai

Nilai adalah ekspresi yang penilaiannya menentukan identiti objek, bidang bit, atau fungsi. Identiti adalah identiti rasmi seperti ident di atas, atau nama rujukan nilai, penunjuk, atau nama fungsi. Pertimbangkan kod berikut yang berfungsi:

int myInt = 512;
int & myRef = myInt;
int * ptr = &myInt;
int fn ()

++ptr; --ptr;
kembalikan myInt;

Di sini, myInt adalah nilai; myRef adalah ungkapan rujukan nilai; * ptr adalah ungkapan lvalue kerana hasilnya dapat dikenal pasti dengan ptr; ++ ptr atau -ptr adalah ungkapan lvalue kerana hasilnya dapat dikenal pasti dengan keadaan baru (alamat) ptr, dan fn adalah lvalue (ungkapan).

Pertimbangkan segmen kod berikut:

int a = 2, b = 8;
int c = a + 16 + b + 64;

Dalam pernyataan kedua, lokasi untuk 'a' mempunyai 2 dan dapat dikenal pasti dengan 'a', dan begitu juga nilai. Lokasi untuk b mempunyai 8 dan dapat dikenalpasti oleh b, begitu juga nilai. Lokasi untuk c akan mempunyai jumlah, dan dapat dikenalpasti oleh c, dan begitu juga nilai. Dalam pernyataan kedua, ungkapan atau nilai 16 dan 64 adalah nilai semula (lihat di bawah).

Pertimbangkan segmen kod berikut:

char seq [5];
seq [0] = 'l', seq [1] = 'o', seq [2] = 'v', seq [3] = 'e', ​​seq [4] = '\ 0';
cout<< seq[2] <<'\n';

Keluarannya adalah 'v';

seq ialah tatasusunan. Lokasi untuk 'v' atau nilai serupa dalam array dikenal pasti oleh seq [i], di mana i adalah indeks. Jadi, ungkapan, seq [i], adalah ungkapan lvalue. seq, yang merupakan pengecam untuk keseluruhan susunan, juga merupakan nilai.

nilai

Prvalue adalah ekspresi yang penilaiannya menginisialisasi objek atau medan bit atau menghitung nilai operasi operator, seperti yang ditentukan oleh konteks di mana ia muncul.

Dalam penyataan tersebut,

int myInt = 256;

256 adalah prvalue (ungkapan prvalue) yang menginisialisasi objek yang dikenal pasti oleh myInt. Objek ini tidak dirujuk.

Dalam penyataan tersebut,

int && ref = 4;

4 adalah prvalue (ungkapan prvalue) yang memulakan objek yang dirujuk oleh ref. Objek ini tidak dikenal pasti secara rasmi. ref adalah contoh ungkapan rujukan rvalue atau ungkapan rujukan prvalue; itu adalah nama, tetapi bukan pengecam rasmi.

Pertimbangkan segmen kod berikut:

int ident;
ident = 6;
int & ref = ident;

6 adalah prvalue yang memulakan objek yang dikenal pasti oleh ident; objek tersebut juga dirujuk oleh ref. Di sini, rujukan adalah rujukan nilai dan bukan rujukan nilai.

Pertimbangkan segmen kod berikut:

int a = 2, b = 8;
int c = a + 15 + b + 63;

15 dan 63 masing-masing adalah pemalar yang mengira dirinya sendiri, menghasilkan operan (dalam bit) untuk operator penambahan. Jadi, 15 atau 63 adalah ungkapan nilai.

Sebarang literal, kecuali string harfiah, adalah nilai awal (i.e., ungkapan nilai). Jadi, harfiah seperti 58 atau 58.53, atau benar atau salah, adalah nilai awal. Literal dapat digunakan untuk menginisialisasi objek atau akan menghitung dirinya sendiri (ke dalam bentuk lain dalam bit) sebagai nilai operan untuk operator. Dalam kod di atas, literal 2 menginisialisasi objek, a. Ia juga mengira dirinya sebagai operasi untuk pengendali tugas.

Mengapa string literal bukan nilai awal? Pertimbangkan kod berikut:

char str [] = "cinta tidak benci";
cout << str <<'\n';
cout << str[5] <<'\n';

Keluarannya adalah:

cinta bukan benci
n

str mengenal pasti keseluruhan rentetan. Jadi, ungkapan, str, dan bukan apa yang dikenalinya, adalah nilai. Setiap watak dalam rentetan dapat dikenali oleh str [i], di mana i adalah indeks. Ungkapan, str [5], dan bukan watak yang dikenalinya, adalah nilai. String literal adalah nilai dan bukan prvalue.

Dalam pernyataan berikut, array literal menginisialisasi objek, arr:

ptrInt ++ atau ptrInt-- 

Di sini, ptrInt adalah penunjuk ke lokasi integer. Keseluruhan ungkapan, dan bukan nilai akhir dari lokasi yang ditunjukkan, adalah nilai (ungkapan). Ini kerana ungkapan, ptrInt ++ atau ptrInt-, mengenal pasti nilai pertama asal lokasinya dan bukan nilai akhir kedua dari lokasi yang sama. Sebaliknya, -ptrInt atau -ptrInt adalah nilai kerana ia mengenal pasti satu-satunya nilai minat di lokasi. Kaedah lain untuk melihatnya adalah bahawa nilai asal mengira nilai akhir kedua.

Dalam pernyataan kedua kod berikut, a atau b masih dapat dianggap sebagai prvalue:

int a = 2, b = 8;
int c = a + 15 + b + 63;

Jadi, a atau b dalam pernyataan kedua adalah nilai kerana ia mengenal pasti objek. Ini juga merupakan nilai kerana ia mengira bilangan bulat operan bagi operator tambahan.

(int baru), dan bukan lokasi yang ditetapkannya adalah nilai. Dalam pernyataan berikut, alamat kembali lokasi diberikan ke objek penunjuk:

int * ptrInt = int baru

Di sini, * ptrInt adalah nilai, sementara (int baru) adalah nilai. Ingat, lvalue atau prvalue adalah ungkapan. (int baru) tidak mengenal pasti objek. Mengembalikan alamat tidak bermaksud mengenal pasti objek dengan nama (seperti ident, di atas). Dalam * ptrInt, nama, ptrInt, adalah yang benar-benar mengenal pasti objek, jadi * ptrInt adalah nilai. Sebaliknya, (int baru) adalah prvalue, kerana ia menghitung lokasi baru ke alamat nilai operan untuk operator penugasan =.

nilai x

Hari ini, lvalue bermaksud Nilai Lokasi; prvalue bermaksud rvalue "murni" (lihat apa maksud rvalue di bawah). Hari ini, xvalue bermaksud lvalue "eXpiring".

Definisi xvalue, dipetik dari spesifikasi C ++, adalah seperti berikut:

"Nilai xvalue adalah nilai glv yang menunjukkan objek atau medan bit yang sumbernya dapat digunakan kembali (biasanya kerana hampir menjelang akhir hayatnya). [Contoh: Jenis ungkapan tertentu yang melibatkan rujukan rvalue menghasilkan nilai xvalu, seperti panggilan ke fungsi yang jenis pengembaliannya adalah rujukan rvalue atau cor ke contoh jenis rujukan nilai akhir] ”

Ini bermaksud bahawa kedua-dua nilai dan nilai boleh habis masa berlakunya. Kod berikut (disalin dari atas) menunjukkan bagaimana penyimpanan (sumber) lvalue, * ptrInt digunakan semula setelah ia dihapus.

int * ptrInt = int baru;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
padamkan ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Keluarannya adalah:

12
0
24

Program berikut (disalin dari atas) menunjukkan bagaimana penyimpanan rujukan integer, yang merupakan rujukan nilai yang dikembalikan oleh fungsi, digunakan kembali dalam fungsi utama ():

#sertakan
menggunakan ruang nama std;
int & fn ()

int i = 5;
int & j = i;
pulangan j;

int utama ()

int & myInt = fn ();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
pulangan 0;

Keluarannya adalah:

5
17

Apabila objek seperti i dalam fungsi fn () keluar dari ruang lingkup, ia secara semula jadi musnah. Dalam kes ini, penyimpanan i masih digunakan semula dalam fungsi utama ().

Dua contoh kod di atas menggambarkan penggunaan semula penyimpanan nilai. Ada kemungkinan untuk menggunakan semula penggunaan prvalues ​​(rvalues) (lihat kemudian).

Petikan berikut mengenai xvalue adalah dari spesifikasi C ++:

"Secara umum, kesan dari peraturan ini adalah bahawa rujukan nilai yang dinamakan diperlakukan sebagai nilai dan rujukan nilai yang tidak disebutkan namanya terhadap objek diperlakukan sebagai nilai x. rvalue rujukan fungsi dianggap sebagai nilai sama ada dinamakan atau tidak." (jumpa lagi).

Jadi, xvalue adalah lvalue atau prvalue yang sumbernya (simpanan) dapat digunakan semula. xvalues ​​adalah himpunan persilangan nilai dan nilai.

Terdapat lebih banyak nilai dari apa yang telah dibahas dalam artikel ini. Walau bagaimanapun, xvalue layak mendapat keseluruhan artikel sendiri, dan spesifikasi tambahan untuk xvalue tidak dibahas dalam artikel ini.

Set Taksonomi Kategori Ekspresi

Petikan lain dari spesifikasi C ++:

"Nota: Dari segi sejarah, nilai dan nilai disebut begitu kerana ia boleh muncul di sebelah kiri dan kanan tugas (walaupun ini tidak lagi berlaku secara umum); nilai glv adalah nilai "umum", nilai adalah nilai "murni", dan nilai x adalah nilai "eXpiring". Walaupun namanya, istilah ini mengklasifikasikan ungkapan, bukan nilai. - nota akhir ”

Jadi, glvalues ​​adalah himpunan kesatuan nilai dan nilai x dan nilai adalah set kesatuan nilai dan nilai. xvalues ​​adalah himpunan persilangan nilai dan nilai.

Setakat ini, taksonomi kategori ungkapan digambarkan dengan lebih baik dengan gambarajah Venn seperti berikut:

Kesimpulannya

Nilai adalah ekspresi yang penilaiannya menentukan identiti objek, bidang bit, atau fungsi.

Prvalue adalah ekspresi yang penilaiannya menginisialisasi objek atau medan bit atau menghitung nilai operasi operator, seperti yang ditentukan oleh konteks di mana ia muncul.

Nilai x adalah nilai atau prvalue, dengan harta tambahan yang sumbernya (simpanan) dapat digunakan kembali.

Spesifikasi C ++ menggambarkan taksonomi kategori ekspresi dengan rajah pohon, yang menunjukkan bahawa terdapat beberapa hierarki dalam taksonomi. Setakat ini, tidak ada hierarki dalam taksonomi, jadi rajah Venn digunakan oleh beberapa pengarang, kerana ia menggambarkan taksonomi lebih baik daripada rajah pohon.

Tiru klik Tetikus dengan melayang menggunakan Mouse Tanpa Klik di Windows 10
Menggunakan tetikus atau papan kekunci dalam keadaan salah penggunaan berlebihan boleh menyebabkan banyak masalah kesihatan, termasuk ketegangan, sind...
Tambahkan isyarat Tetikus ke Windows 10 menggunakan alat percuma ini
Dalam beberapa tahun kebelakangan ini komputer dan sistem operasi telah banyak berkembang. Ada saat ketika pengguna harus menggunakan perintah untuk m...
Mengawal & menguruskan pergerakan tetikus antara beberapa monitor di Windows 10
Pengurus Tetikus Paparan Dwi membolehkan anda mengawal & mengkonfigurasi pergerakan tetikus antara beberapa monitor, dengan memperlahankan pergerakann...