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 perhitungan. 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. Ketika 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. 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 antara 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 memerlukan 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 useran kembali a sumber.

Lokasi dan Objek

Perhatikan deklarasi berikut:

int ident;

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 integer untuk engine 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 (konten) 5, dan pengidentifikasi kedua memiliki nilai 100. Dalam engine 32bit, masing-masing lokasi ini panjangnya empat byte. Pengidentifikasi pertama mengidentifikasi lokasi dan nilai. Pengidentifikasi kedua juga mengidentifikasi keduanya.

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

Penyimpanan Objek dan Sumber Daya

Lokasi suatu objek disebut juga sebagai tempat penyimpanan atau resource dari objek tersebut.

inisialisasi

Perhatikan segmen kode berikut:

int ident;

ident = 8;

Baris pertama mendeklarasikan pengenal. Deklarasi ini menyediakan lokasi (penyimpanan atau sumber daya) untuk objek integer, mengidentifikasinya dengan nama, i
dent. 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::vector vtr{1, 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 ident = 4;

int& ref1 = ident;

int& ref2 = ident;

cout<< ident <<' '<< ref1 <<' '<< ref2 << 'n';

Outputnya adalah:

4 4 4

ident adalah pengidentifikasi, sedangkan ref1 dan ref2 adalah referensi; mereka merujuk lokasi yang sama. 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 nama lokasi yang sama.

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

lnilai Referensi dan rnilai Referensi

Cara normal untuk membuat referensi adalah sebagai berikut:

int ident;

ident = 4;

int& ref = ident;

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, copyan pengidentifikasi akan dibuat dalam fungsi, sedangkan untuk kasus referensi, lokasi asli akan digunakan (dirujuk) dalam fungsi.

Saat ini, dimungkinkan untuk hanya memiliki referensi tanpa mengidentifikasinya. Artinya, dimungkinkan untuk membuat referensi terlebih dahulu tanpa memiliki pengenal 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 Anda menggunakan 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 dicopy 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 penunjuk. Untuk mengembalikan (memperoleh) nilai objek runcing, gunakan pengenal objek penunjuk, seperti pada “*ptrInt”.

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

Baris kedua dan ketiga dalam kode di atas dapat dikurangi 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:

new int

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

int *ptrInt = new int;

*ptrInt = 12;

cout<< *ptrInt  <<'n';

Keluarannya adalah 12.

Untuk menghancurkan objek, gunakan ekspresi delete sebagai berikut:

delete ptrInt;

Argumen untuk ekspresi delete adalah pointer. Kode berikut mengilustrasikan userannya:

int *ptrInt = new int;

*ptrInt = 12;

delete 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 = new int;

*ptrInt = 12;

cout<< *ptrInt <<'n';

delete 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:

#include <iostream>

using namespace std;

int& fn()

{

int i = 5;

int& j = i;

return j;

}

int main()

{

int& myInt = fn();

cout<< myInt <<'n';

myInt = 17;

cout<< myInt <<'n';

return 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()

{

++ptr; --ptr;

return 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 juga merupakan 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 juga nilai. Dalam pernyataan kedua, ekspresi atau nilai dari 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]=' ';

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 tersebut,

int myInt = 256;

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

Dalam pernyataan tersebut,

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, tetapi bukan pengenal resmi.

Perhatikan segmen kode berikut:

int ident;

ident = 6;

int& ref = ident;

6 adalah nilai yang menginisialisasi objek yang diidentifikasi oleh ident; objek juga dirujuk oleh ref. Di sini, ref 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 prvalue (yaitu, ekspresi prvalue). Jadi, literal seperti 58 atau 58,53, atau benar atau salah, adalah nilai awal. 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[] = "love not hate";

cout << str <<'n';

cout << str[5] <<'n';

Outputnya adalah:

love not hate

n

str mengidentifikasi seluruh string. Jadi, ekspresi, str, dan bukan yang diidentifikasi, adalah nilai. 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++ or  ptrInt-- 

Di sini, ptrInt adalah penunjuk ke lokasi integer. 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 yang diminati 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.

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

int *ptrInt = new int

Di sini, *ptrInt adalah lvalue, sedangkan (new int) adalah prvalue. Ingat, lvalue atau prvalue adalah ekspresi. (int baru) tidak mengidentifikasi objek apa pun. Mengembalikan alamat tidak berarti mengidentifikasi objek dengan nama (seperti ident, di atas). Dalam *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 jenis referensi nilai— contoh akhir]”

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

int *ptrInt = new int;

*ptrInt = 12;

cout<< *ptrInt <<'n';

delete ptrInt;

cout<< *ptrInt <<'n';

*ptrInt = 24;

cout<< *ptrInt <<'n';

Outputnya adalah:

12

0

24

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

#include <iostream>

using namespace std;

int& fn()

{

int i = 5;

int& j = i;

return j;

}

int main()

{

int& myInt = fn();

cout<< myInt <<'n';

myInt = 17;

cout<< myInt <<'n';

return 0;

}

Outputnya adalah:

5

17

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

Dua contoh kode di atas menggambarkan useran kembali penyimpanan nilai. Dimungkinkan untuk memiliki penyimpanan useran 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++:

Note: Secara historis, lvalues ​​dan rvalues ​​disebut demikian karena mereka dapat muncul di sisi kiri dan kanan dari sebuah tugas (walaupun hal ini tidak lagi berlaku secara umum); glvalues ​​adalah “generalized” lvalues, prvalues ​​adalah rvalues ​​”murni”, dan xvalues ​​adalah “eXpiring” lvalues. 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. Sampai sekarang, tidak ada hierarki dalam taksonomi, sehingga diagram Venn digunakan oleh beberapa penulis, karena menggambarkan taksonomi lebih baik daripada diagram pohon.

Related Posts