C++

Taksonomi Kategori Ekspresi dalam C++

Taksonomi Kategori Ekspresi dalam C++

Perhitungan adalah semua jenis perhitungan yang mengikuti algoritma yang terdefinisi dengan baik. Ekspresi adalah urutan operator dan operan yang menentukan komputasi. Dengan kata lain, ekspresi adalah pengidentifikasi atau literal, atau urutan keduanya, yang digabungkan oleh operator.Dalam pemrograman, ekspresi dapat menghasilkan nilai dan/atau menyebabkan beberapa kejadian. Saat menghasilkan nilai, ekspresinya adalah nilai gl, nilai, nilai, nilai x, atau nilai. Masing-masing kategori ini adalah satu set ekspresi. Setiap set memiliki definisi dan situasi tertentu di mana maknanya berlaku, membedakannya dari set lain another. Setiap set disebut kategori nilai.

Catatan: Nilai atau literal masih merupakan ekspresi, jadi istilah ini mengklasifikasikan ekspresi dan bukan nilai sebenarnya.

glvalue dan rvalue adalah dua himpunan bagian dari ekspresi himpunan besar. glvalue ada dalam dua himpunan bagian lebih lanjut: lvalue dan xvalue. rvalue, subset lain untuk ekspresi, juga ada di dua subset lebih lanjut: xvalue dan prvalue. Jadi, xvalue adalah himpunan bagian dari glvalue dan rvalue: yaitu, xvalue adalah perpotongan dari glvalue dan rvalue. Diagram taksonomi berikut, diambil dari spesifikasi C++, menggambarkan hubungan semua himpunan:

prvalue, xvalue, dan lvalue adalah nilai kategori utama. glvalue adalah gabungan dari lvalues ​​dan xvalues, sedangkan rvalues ​​adalah gabungan dari xvalues ​​dan prvalues.

Anda membutuhkan pengetahuan dasar dalam C++ untuk memahami artikel ini; Anda juga membutuhkan pengetahuan tentang Lingkup dalam C++.

Isi Artikel

Dasar-dasar

Untuk benar-benar memahami taksonomi kategori ekspresi, Anda perlu mengingat atau mengetahui fitur dasar berikut terlebih dahulu: lokasi dan objek, penyimpanan dan sumber daya, inisialisasi, pengenal dan referensi, referensi nilai dan nilai, penunjuk, penyimpanan gratis, dan penggunaan kembali sebuah sumber.

Lokasi dan Objek

Perhatikan deklarasi berikut:

int identitas;

Ini adalah deklarasi yang mengidentifikasi lokasi di memori. Lokasi adalah sekumpulan byte berurutan tertentu dalam memori. Lokasi dapat terdiri dari satu byte, dua byte, empat byte, enam puluh empat byte, dll. Lokasi bilangan bulat untuk mesin 32bit adalah empat byte. Juga, lokasi dapat diidentifikasi dengan pengidentifikasi.

Dalam deklarasi di atas, lokasi tidak memiliki konten apa pun. Artinya tidak ada nilainya, karena isinya adalah nilainya. Jadi, pengidentifikasi mengidentifikasi lokasi (ruang kecil terus menerus). Ketika lokasi diberi konten tertentu, pengidentifikasi kemudian mengidentifikasi lokasi dan konten; yaitu, pengidentifikasi kemudian mengidentifikasi lokasi dan nilainya.

Perhatikan pernyataan berikut:

int ident1 = 5;
int ident2 = 100;

Masing-masing pernyataan ini adalah deklarasi dan definisi. Pengidentifikasi pertama memiliki nilai (isi) 5, dan pengidentifikasi kedua memiliki nilai 100. Dalam mesin 32bit, masing-masing lokasi ini memiliki panjang empat byte. Pengidentifikasi pertama mengidentifikasi lokasi dan nilai. Pengidentifikasi kedua juga mengidentifikasi keduanya.

Objek adalah wilayah bernama penyimpanan dalam memori. Jadi, suatu objek adalah lokasi tanpa nilai atau lokasi dengan nilai.

Penyimpanan Objek dan Sumber Daya

Lokasi untuk suatu objek juga disebut penyimpanan atau sumber daya objek.

inisialisasi

Perhatikan segmen kode berikut:

int identitas;
identitas = 8;

Baris pertama mendeklarasikan pengenal. Deklarasi ini menyediakan lokasi (penyimpanan atau sumber daya) untuk objek integer, mengidentifikasinya dengan nama, ident. Baris berikutnya menempatkan nilai 8 (dalam bit) ke lokasi yang diidentifikasi oleh ident. Penempatan nilai ini adalah inisialisasi.

Pernyataan berikut mendefinisikan vektor dengan konten, 1, 2, 3, 4, 5, diidentifikasi oleh vtr:

std::vtrvtr1, 2, 3, 4, 5;

Di sini, inisialisasi dengan 1, 2, 3, 4, 5 dilakukan dalam pernyataan definisi yang sama (deklarasi). Operator penugasan tidak digunakan. Pernyataan berikut mendefinisikan array dengan konten 1, 2, 3, 4, 5:

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

Kali ini, operator penugasan telah digunakan untuk inisialisasi.

Pengenal dan Referensi

Perhatikan segmen kode berikut:

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

Outputnya adalah:

4 4 4

ident adalah pengidentifikasi, sedangkan ref1 dan ref2 adalah referensi; mereka merujuk lokasi yang sama same. Referensi adalah sinonim untuk pengidentifikasi. Secara konvensional, ref1 dan ref2 adalah nama yang berbeda dari satu objek, sedangkan ident adalah pengidentifikasi dari objek yang sama. Namun, ident tetap bisa disebut nama objek, yang artinya, ident, ref1, dan ref2 menamai lokasi yang sama.

Perbedaan utama antara pengidentifikasi dan referensi adalah bahwa, ketika diteruskan sebagai argumen ke suatu fungsi, jika diteruskan oleh pengidentifikasi, salinan dibuat untuk pengidentifikasi dalam fungsi, sedangkan jika diteruskan dengan referensi, lokasi yang sama digunakan dalam fungsi. Jadi, melewati pengenal berakhir dengan dua lokasi, sementara melewati referensi berakhir dengan satu lokasi yang sama.

Referensi nilai dan Referensi nilai

Cara normal untuk membuat referensi adalah sebagai berikut:

int identitas;
identitas = 4;
int& ref = identitas;

Penyimpanan (sumber daya) ditempatkan dan diidentifikasi terlebih dahulu (dengan nama seperti ident), dan kemudian dibuat referensi (dengan nama seperti ref). Saat meneruskan sebagai argumen ke suatu fungsi, salinan pengidentifikasi akan dibuat dalam fungsi, sedangkan untuk kasus referensi, lokasi asli akan digunakan (dirujuk) dalam fungsi.

Hari ini, dimungkinkan untuk hanya memiliki referensi tanpa mengidentifikasinya. Ini berarti dimungkinkan untuk membuat referensi terlebih dahulu tanpa memiliki pengenal untuk lokasi. Ini menggunakan &&, seperti yang ditunjukkan dalam pernyataan berikut:

int&& ref = 4;

Di sini, tidak ada identifikasi sebelumnya. Untuk mengakses nilai objek, cukup gunakan ref seperti yang Anda gunakan ident di atas.

Dengan deklarasi &&, tidak ada kemungkinan meneruskan argumen ke fungsi dengan pengidentifikasi. Satu-satunya pilihan adalah lulus dengan referensi. Dalam hal ini, hanya ada satu lokasi yang digunakan dalam fungsi dan bukan lokasi yang disalin kedua seperti pengidentifikasi.

Deklarasi referensi dengan & disebut referensi lvalue. Deklarasi referensi dengan && disebut referensi nilai, yang juga merupakan referensi nilai (lihat di bawah).

penunjuk

Perhatikan kode berikut:

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

Keluarannya adalah 5.

Di sini, ptdInt adalah pengenal seperti ident di atas. Ada dua objek (lokasi) di sini, bukan satu: objek runcing, ptdInt diidentifikasi oleh ptdInt, dan objek penunjuk, ptrInt diidentifikasi oleh ptrInt. &ptdInt mengembalikan alamat objek yang ditunjuk dan menempatkannya sebagai nilai dalam objek ptrInt pointer. Untuk mengembalikan (memperoleh) nilai objek runcing, gunakan pengenal objek penunjuk, seperti pada “*ptrInt”.

Catatan: ptdInt adalah pengenal dan bukan referensi, sedangkan nama, ref, disebutkan sebelumnya, adalah referensi.

Baris kedua dan ketiga dalam kode di atas dapat direduksi menjadi satu baris, yang mengarah ke kode berikut:

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

Catatan: Ketika sebuah pointer bertambah, itu menunjuk ke lokasi berikutnya, yang bukan merupakan penambahan nilai 1. Ketika sebuah pointer dikurangi, itu menunjuk ke lokasi sebelumnya, yang bukan merupakan pengurangan dari nilai 1.

Toko Gratis

Sistem operasi mengalokasikan memori untuk setiap program yang sedang berjalan. Memori yang tidak dialokasikan untuk program apa pun dikenal sebagai penyimpanan gratis. Ekspresi yang mengembalikan lokasi untuk bilangan bulat dari penyimpanan gratis adalah:

int baru

Ini mengembalikan lokasi untuk bilangan bulat yang tidak diidentifikasi. Kode berikut mengilustrasikan cara menggunakan pointer dengan toko gratis:

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

Keluarannya adalah 12.

Untuk menghancurkan objek, gunakan ekspresi delete sebagai berikut:

hapus ptrInt;

Argumen untuk ekspresi hapus adalah pointer. Kode berikut mengilustrasikan penggunaannya:

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

Keluarannya adalah 0, dan bukan sesuatu seperti null atau undefined. delete menggantikan nilai lokasi dengan nilai default jenis lokasi tertentu, lalu mengizinkan lokasi untuk digunakan kembali. Nilai default untuk lokasi int adalah 0.

Menggunakan kembali Sumber Daya

Dalam taksonomi kategori ekspresi, menggunakan kembali sumber daya sama dengan menggunakan kembali lokasi atau penyimpanan untuk suatu objek. Kode berikut mengilustrasikan bagaimana lokasi dari toko gratis dapat digunakan kembali:

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

Outputnya adalah:

12
0
24

Nilai 12 pertama kali ditetapkan ke lokasi yang tidak dikenal. Kemudian konten lokasi dihapus (secara teori objek dihapus). Nilai 24 ditugaskan kembali ke lokasi yang sama.

Program berikut menunjukkan bagaimana referensi integer yang dikembalikan oleh suatu fungsi digunakan kembali:

#termasuk
menggunakan namespace std;
int & fn()

int saya = 5;
int& j = saya;
kembali j;

int utama()

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

Outputnya adalah:

5
17

Objek seperti i, dideklarasikan dalam lingkup lokal (lingkup fungsi), tidak ada lagi di akhir lingkup lokal. Namun, fungsi fn() di atas, mengembalikan referensi i. Melalui referensi yang dikembalikan ini, nama, myInt dalam fungsi main(), menggunakan kembali lokasi yang diidentifikasi oleh i untuk nilai 17.

nilai

Nilai adalah ekspresi yang evaluasinya menentukan identitas suatu objek, bidang bit, atau fungsi. Identitas adalah identitas resmi seperti ident di atas, atau nama referensi nilai, pointer, atau nama fungsi. Pertimbangkan kode berikut yang berfungsi:

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

++PT; --ptr;
kembali myInt;

Di sini, myInt adalah lvalue; myRef adalah ekspresi referensi nilai; *ptr adalah ekspresi lvalue karena hasilnya dapat diidentifikasi dengan ptr; ++ptr atau -ptr adalah ekspresi nilai karena hasilnya dapat diidentifikasi dengan status baru (alamat) ptr, dan fn adalah nilai (ekspresi).

Perhatikan segmen kode berikut:

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

Dalam pernyataan kedua, lokasi untuk 'a' memiliki 2 dan dapat diidentifikasi oleh 'a', dan begitu juga nilai. Lokasi untuk b memiliki 8 dan dapat diidentifikasi oleh b, dan begitu juga dengan nilai. Lokasi untuk c akan memiliki jumlah, dan dapat diidentifikasi oleh c, dan begitu juga nilai. Dalam pernyataan kedua, ekspresi atau nilai 16 dan 64 adalah nilai (lihat di bawah).

Perhatikan segmen kode 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 adalah array. Lokasi untuk 'v' atau nilai serupa dalam array diidentifikasi dengan seq[i], di mana i adalah indeks. Jadi, ekspresi, seq[i], adalah ekspresi nilai. seq, yang merupakan pengidentifikasi untuk seluruh array, juga merupakan nilai.

nilai awal

Pranilai adalah ekspresi yang evaluasinya menginisialisasi objek atau bidang bit atau menghitung nilai operan operator, seperti yang ditentukan oleh konteks di mana ia muncul.

Dalam pernyataan,

int myInt = 256;

256 adalah nilai awal (ekspresi nilai) yang menginisialisasi objek yang diidentifikasi oleh myInt. Objek ini tidak dirujuk.

Dalam pernyataan,

int&& ref = 4;

4 adalah prvalue (ekspresi prvalue) yang menginisialisasi objek yang direferensikan oleh ref. Objek ini tidak diidentifikasi secara resmi. ref adalah contoh ekspresi referensi nilai atau ekspresi referensi nilai; itu adalah nama, tapi bukan pengenal resmi official.

Perhatikan segmen kode berikut:

int identitas;
identitas = 6;
int& ref = identitas;

6 adalah nilai yang menginisialisasi objek yang diidentifikasi oleh ident; objek juga dirujuk oleh ref. Di sini, referensi adalah referensi nilai dan bukan referensi nilai.

Perhatikan segmen kode berikut:

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

15 dan 63 masing-masing adalah konstanta yang menghitung dirinya sendiri, menghasilkan operan (dalam bit) untuk operator penambahan. Jadi, 15 atau 63 adalah ekspresi nilai.

Setiap literal, kecuali string literal, adalah nilai awal (i.e., ekspresi nilai). Jadi, literal seperti 58 atau 58.53, atau benar atau salah, adalah nilai. Sebuah literal dapat digunakan untuk menginisialisasi suatu objek atau akan menghitung untuk dirinya sendiri (ke dalam beberapa bentuk lain dalam bit) sebagai nilai operan untuk operator. Dalam kode di atas, literal 2 menginisialisasi objek, a. Itu juga menghitung dirinya sendiri sebagai operan untuk operator penugasan.

Mengapa string literal bukan nilai?? Perhatikan kode berikut:

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

Outputnya adalah:

cinta bukan benci
tidak

str mengidentifikasi seluruh string. Jadi, ekspresi, str, dan bukan yang diidentifikasi, adalah lvalue. Setiap karakter dalam string dapat diidentifikasi dengan str[i], di mana i adalah indeks. Ekspresi, str[5], dan bukan karakter yang diidentifikasinya, adalah nilai. String literal adalah lvalue dan bukan prvalue.

Dalam pernyataan berikut, literal array menginisialisasi objek, arr:

ptrInt++ atau  ptrInt-- 

Di sini, ptrInt adalah penunjuk ke lokasi bilangan bulat. Seluruh ekspresi, dan bukan nilai akhir dari lokasi yang ditunjuknya, adalah nilai awal (ekspresi). Ini karena ekspresi, ptrInt++ atau ptrInt-, mengidentifikasi nilai pertama asli dari lokasinya dan bukan nilai akhir kedua dari lokasi yang sama. Di sisi lain, -ptrInt atau  -ptrInt adalah nilai karena mengidentifikasi satu-satunya nilai minat di lokasi. Cara lain untuk melihatnya adalah bahwa nilai asli menghitung nilai akhir kedua.

Dalam pernyataan kedua dari kode berikut, a atau b masih dapat dianggap sebagai nilai awal:

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

Jadi, a atau b dalam pernyataan kedua adalah nilai karena mengidentifikasi suatu objek. Ini juga merupakan nilai karena menghitung bilangan bulat operan untuk operator penambahan addition.

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

int *ptrInt = int baru

Di sini, *ptrInt adalah nilai, sedangkan (int baru) adalah nilai. Ingat, nilai atau nilai adalah ekspresi. (int baru) tidak mengidentifikasi objek apa pun. Mengembalikan alamat tidak berarti mengidentifikasi objek dengan nama (seperti ident, di atas). Di *ptrInt, nama, ptrInt, adalah yang benar-benar mengidentifikasi objek, jadi *ptrInt adalah nilai. Di sisi lain, (int baru) adalah nilai awal, karena menghitung lokasi baru ke alamat nilai operan untuk operator penugasan =.

nilai x

Hari ini, lvalue adalah singkatan dari Location Value; prvalue adalah singkatan dari rvalue "murni" (lihat apa singkatan dari rvalue di bawah). Hari ini, xvalue adalah singkatan dari "eXpiring" lvalue.

Definisi nilai x, dikutip dari spesifikasi C++, adalah sebagai berikut:

“Nilai x adalah nilai gl yang menunjukkan objek atau bidang bit yang sumber dayanya dapat digunakan kembali (biasanya karena mendekati akhir masa pakainya). [Contoh: Jenis ekspresi tertentu yang melibatkan referensi nilai menghasilkan nilai x, seperti panggilan ke fungsi yang tipe pengembaliannya adalah referensi nilai atau dilemparkan ke contoh tipe referensi nilai akhir]”

Artinya, nilai dan nilai dapat kedaluwarsa. Kode berikut (disalin dari atas) menunjukkan bagaimana penyimpanan (sumber daya) lvalue, *ptrInt digunakan kembali setelah dihapus.

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

Outputnya adalah:

12
0
24

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

#termasuk
menggunakan namespace std;
int & fn()

int saya = 5;
int& j = saya;
kembali j;

int utama()

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

Outputnya adalah:

5
17

Ketika objek seperti i dalam fungsi fn() keluar dari ruang lingkup, objek tersebut secara alami dihancurkan. Dalam hal ini, penyimpanan i masih digunakan kembali dalam fungsi main().

Dua contoh kode di atas menggambarkan penggunaan kembali penyimpanan nilai. Dimungkinkan untuk memiliki penyimpanan penggunaan kembali nilai-nilai (nilai-nilai) (lihat nanti).

Kutipan berikut tentang xvalue berasal dari spesifikasi C++:

“Secara umum, efek dari aturan ini adalah bahwa referensi rvalue bernama diperlakukan sebagai lvalues ​​dan referensi rvalue yang tidak disebutkan namanya ke objek diperlakukan sebagai xvalues. referensi nilai ke fungsi diperlakukan sebagai nilai baik bernama atau tidak." (sampai nanti).

Jadi, nilai x adalah nilai atau nilai yang sumber dayanya (penyimpanan) dapat digunakan kembali. xvalues ​​adalah himpunan persimpangan lvalues ​​dan prvalues.

Ada lebih banyak nilai x daripada apa yang telah dibahas dalam artikel ini. Namun, xvalue layak mendapatkan seluruh artikel tersendiri, sehingga spesifikasi tambahan untuk xvalue tidak dibahas dalam artikel ini.

Set Taksonomi Kategori Ekspresi

Kutipan lain dari spesifikasi C++:

Catatan: Secara historis, lvalues ​​dan rvalues ​​disebut demikian karena mereka dapat muncul di sisi kiri dan kanan dari suatu tugas (walaupun hal ini tidak lagi berlaku secara umum); glvalues ​​adalah lvalues ​​"digeneralisasi", prvalues ​​adalah rvalues ​​"murni", dan xvalues ​​adalah lvalues ​​"eXpiring". Terlepas dari namanya, istilah-istilah ini mengklasifikasikan ekspresi, bukan nilai. - catatan akhir”

Jadi, glvalues ​​adalah himpunan gabungan dari lvalues ​​dan xvalues ​​dan rvalues ​​adalah himpunan union dari xvalues ​​dan prvalues. xvalues ​​adalah himpunan persimpangan lvalues ​​dan prvalues.

Sampai sekarang, taksonomi kategori ekspresi lebih baik diilustrasikan dengan diagram Venn sebagai berikut:

Kesimpulan

Nilai adalah ekspresi yang evaluasinya menentukan identitas suatu objek, bidang bit, atau fungsi.

Pranilai adalah ekspresi yang evaluasinya menginisialisasi objek atau bidang bit atau menghitung nilai operan operator, seperti yang ditentukan oleh konteks di mana ia muncul.

Nilai x adalah nilai atau nilai, dengan properti tambahan yang sumber dayanya (penyimpanan) dapat digunakan kembali.

Spesifikasi C++ menggambarkan taksonomi kategori ekspresi dengan diagram pohon, yang menunjukkan bahwa ada beberapa hierarki dalam taksonomi tax. Sampai sekarang, tidak ada hierarki dalam taksonomi, sehingga diagram Venn digunakan oleh beberapa penulis, karena menggambarkan taksonomi lebih baik daripada diagram pohon.

Cara membalikkan arah gulir Mouse dan Touchpads di Windows 10
Mouse dan Panel sentuhs tidak hanya membuat komputasi menjadi mudah tetapi juga lebih efisien dan tidak memakan banyak waktu. Kami tidak dapat membaya...
Cara mengubah penunjuk Mouse dan ukuran kursor, warna & skema pada Windows 10
Penunjuk mouse dan kursor di Windows 10 adalah aspek yang sangat penting dari sistem operasi. Ini dapat dikatakan untuk sistem operasi lain juga, jadi...
Mesin Game Gratis dan Sumber Terbuka untuk Mengembangkan Game Linux
Artikel ini akan membahas daftar mesin game sumber terbuka dan gratis yang dapat digunakan untuk mengembangkan game 2D dan 3D di Linux. Ada banyak mes...