C++

C++'da İfade Kategorisi Taksonomisi

C++'da İfade Kategorisi Taksonomisi

Hesaplama, iyi tanımlanmış bir algoritmayı izleyen herhangi bir hesaplama türüdür. Bir ifade, bir hesaplamayı belirten bir dizi işleç ve işlenendir. Başka bir deyişle, bir ifade, operatörler tarafından birleştirilen bir tanımlayıcı veya değişmez veya her ikisinin bir dizisidir.Programlamada, bir ifade bir değere neden olabilir ve/veya bazı şeylerin olmasına neden olabilir. Bir değerle sonuçlandığında, ifade bir değer, değer, değer, xdeğer veya değerdir. Bu kategorilerin her biri bir dizi ifadedir. Her kümenin bir tanımı ve anlamının baskın olduğu, onu diğer kümeden ayıran özel durumları vardır. Her küme bir değer kategorisi olarak adlandırılır.

Not: Bir değer veya hazır bilgi hala bir ifadedir, bu nedenle bu terimler ifadeleri sınıflandırır, gerçek değerleri değil.

glvalue ve rvalue, büyük küme ifadesinin iki alt kümesidir. glvalue iki alt kümede daha bulunur: lvalue ve xvalue. ifadenin diğer alt kümesi olan rvalue, ayrıca iki alt kümede daha bulunur: xvalue ve prvalue. Yani, xdeğeri hem değer hem de değerin bir alt kümesidir: yani, xdeğeri hem değer hem de değerin kesişimidir. C++ belirtiminden alınan aşağıdaki taksonomi diyagramı, tüm kümelerin ilişkisini gösterir:

prvalue, xvalue ve lvalue birincil kategori değerleridir. glvalue, değerler ve x değerlerinin birleşimidir, değerler ise x değerleri ve değerlerin birleşimidir.

Bu makaleyi anlamak için temel C++ bilgisine ihtiyacınız var; ayrıca C'de Kapsam bilgisine de ihtiyacınız var++.

Makale İçeriği

Temel bilgiler

İfade kategorisi sınıflandırmasını gerçekten anlamak için, öncelikle aşağıdaki temel özellikleri hatırlamanız veya bilmeniz gerekir: konum ve nesne, depolama ve kaynak, başlatma, tanımlayıcı ve referans, değer ve değer referansları, işaretçi, ücretsiz depolama ve bir kaynak.

Konum ve Nesne

Aşağıdaki beyanı göz önünde bulundurun:

int kimliği;

Bu, bellekteki bir konumu tanımlayan bir bildirimdir. Konum, bellekteki belirli bir ardışık bayt kümesidir. Bir konum bir bayt, iki bayt, dört bayt, altmış dört bayt vb. içerebilir. 32 bitlik bir makine için bir tamsayının konumu dört bayttır. Ayrıca, konum bir tanımlayıcı ile tanımlanabilir.

Yukarıdaki beyanda, konumun herhangi bir içeriği yoktur. İçerik değer olduğu için herhangi bir değeri olmadığı anlamına gelir. Böylece, bir tanımlayıcı bir konumu tanımlar (küçük sürekli alan). Konum belirli bir içerik verildiğinde, tanımlayıcı hem konumu hem de içeriği tanımlar; yani, tanımlayıcı daha sonra hem konumu hem de değeri tanımlar.

Aşağıdaki ifadeleri göz önünde bulundurun:

int ident1 = 5;
int ident2 = 100;

Bu ifadelerin her biri bir beyan ve bir tanımdır. İlk tanımlayıcı (içerik) 5 değerine ve ikinci tanımlayıcı 100 değerine sahiptir. 32 bitlik bir makinede bu konumların her biri dört bayt uzunluğundadır. İlk tanımlayıcı hem bir konumu hem de bir değeri tanımlar. İkinci tanımlayıcı ayrıca her ikisini de tanımlar.

Bir nesne, bellekte adlandırılmış bir depolama bölgesidir. Yani bir nesne ya değeri olmayan bir konumdur ya da değeri olan bir konumdur.

Nesne Depolama ve Kaynak

Bir nesnenin konumu, nesnenin deposu veya kaynağı olarak da adlandırılır.

başlatma

Aşağıdaki kod segmentini göz önünde bulundurun:

int kimliği;
özdeş = 8;

İlk satır bir tanımlayıcı bildirir. Bu bildirim, bir tamsayı nesnesi için bir konum (depolama veya kaynak) sağlar ve onu ad, ident ile tanımlar. Sonraki satır, 8 değerini (bit olarak) ident tarafından tanımlanan konuma koyar. Bu değerin koyulması başlatmadır.

Aşağıdaki ifade, vtr tarafından tanımlanan 1, 2, 3, 4, 5 içerikli bir vektörü tanımlar:

std::vektör vtr1, 2, 3, 4, 5;

Burada 1, 2, 3, 4, 5 ile başlatma, tanımın (bildirinin) aynı ifadesinde yapılır. Atama operatörü kullanılmaz. Aşağıdaki ifade 1, 2, 3, 4, 5 içerikli bir diziyi tanımlar:

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

Bu sefer, başlatma için bir atama operatörü kullanıldı.

Tanımlayıcı ve Referans

Aşağıdaki kod segmentini göz önünde bulundurun:

int kimlik = 4;
int& ref1 = özdeş;
int& ref2 = özdeş;
cout<< ident <<"<< ref1 <<"<< ref2 << '\n';

Çıktı:

4 4 4

ident bir tanımlayıcıdır, ref1 ve ref2 referanslardır; aynı yere referans veriyorlar. Referans, tanımlayıcının eş anlamlısıdır. Geleneksel olarak, ref1 ve ref2 bir nesnenin farklı adlarıdır, ident ise aynı nesnenin tanımlayıcısıdır. Bununla birlikte, ident yine de nesnenin adı olarak adlandırılabilir; bu, ident, ref1 ve ref2 aynı konumun adı anlamına gelir.

Tanımlayıcı ile referans arasındaki temel fark, bir fonksiyona argüman olarak iletildiğinde, tanımlayıcı tarafından iletilirse, fonksiyondaki tanımlayıcı için bir kopya yapılması, referans ile iletilirse aynı konumun içinde kullanılmasıdır. fonksiyon. Bu nedenle, tanımlayıcı ile geçiş iki konumla sonlanırken, referansla geçiş aynı konumla sona erer.

değer Referansı ve değer Referansı

Referans oluşturmanın normal yolu aşağıdaki gibidir:

int kimliği;
özdeş = 4;
int&başvuru = kimlik;

Önce depolama (kaynak) bulunur ve tanımlanır (ident gibi bir adla) ve ardından bir referans (ref gibi bir adla) yapılır. Bir fonksiyona argüman olarak iletildiğinde, fonksiyonda tanımlayıcının bir kopyası yapılır, referans olması durumunda ise fonksiyonda orijinal konum kullanılır (başvurulur).

Bugün, tanımlamadan sadece bir referansa sahip olmak mümkündür. Bu, konum için bir tanımlayıcıya sahip olmadan önce bir referans oluşturmanın mümkün olduğu anlamına gelir. Bu, aşağıdaki ifadede gösterildiği gibi && kullanır:

int&& referans = 4;

Burada, önceki bir tanımlama yok. Nesnenin değerine erişmek için, yukarıdaki ident'i kullandığınız gibi ref'yi kullanmanız yeterlidir.

&& bildirimi ile, bir fonksiyona tanımlayıcı ile bir argüman iletme imkanı yoktur. Tek seçenek referans ile geçmek. Bu durumda, bir tanımlayıcıda olduğu gibi, işlev içinde kullanılan ikinci kopyalanan konum değil, yalnızca bir konum vardır.

& içeren bir referans bildirimine değer referansı denir. && içeren bir referans bildirimi, aynı zamanda bir değer referansı olan değer referansı olarak adlandırılır (aşağıya bakın).

Işaretçi

Aşağıdaki kodu göz önünde bulundurun:

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

çıktı 5.

Burada ptdInt, yukarıdaki ident gibi bir tanımlayıcıdır. Burada bir yerine iki nesne (konum) vardır: ptdInt tarafından tanımlanan sivri uçlu nesne, ptdInt tarafından tanımlanan ptrInt ve ptrInt tarafından tanımlanan işaretçi nesnesi. &ptdInt, sivri uçlu nesnenin adresini döndürür ve onu değer olarak ptrInt işaretçi nesnesine koyar. Sivri uçlu nesnenin değerini döndürmek (elde etmek) için, “*ptrInt” de olduğu gibi işaretçi nesnesinin tanımlayıcısını kullanın.

Not: ptdInt bir tanımlayıcıdır ve referans değildir, daha önce bahsedilen ref adı bir referanstır.

Yukarıdaki koddaki ikinci ve üçüncü satırlar bir satıra indirgenebilir ve bu da aşağıdaki koda yol açar:

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

Not: Bir işaretçi artırıldığında, 1 değerinin toplamı olmayan bir sonraki konumu işaret eder. Bir işaretçi azaltıldığında, 1 değerinin çıkarılması olmayan bir önceki konuma işaret eder.

Ücretsiz Mağaza

Bir işletim sistemi, çalışan her program için bellek ayırır. Herhangi bir programa ayrılmamış bir bellek, ücretsiz mağaza olarak bilinir. Ücretsiz mağazadan bir tamsayı için konum döndüren ifade şudur:

yeni int

Bu, tanımlanmayan bir tamsayı için bir konum döndürür. Aşağıdaki kod, işaretçinin ücretsiz mağaza ile nasıl kullanılacağını gösterir:

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

çıktı 12.

Nesneyi yok etmek için aşağıdaki gibi silme ifadesini kullanın:

ptrInt'i sil;

Silme ifadesinin argümanı bir işaretçidir. Aşağıdaki kod, kullanımını göstermektedir:

int *ptrInt = yeni int;
*ptrInt = 12;
ptrInt'i sil;
cout<< *ptrInt <<'\n';

çıktı 0, ve boş veya tanımsız gibi bir şey değil. delete, konumun değerini konumun belirli türünün varsayılan değeriyle değiştirir ve ardından konumun yeniden kullanılmasına izin verir. Bir int konumu için varsayılan değer 0'dır.

Bir Kaynağı Yeniden Kullanmak

İfade kategorisi sınıflandırmasında, bir kaynağı yeniden kullanmak, bir nesne için bir konumu veya depolamayı yeniden kullanmakla aynıdır. Aşağıdaki kod, ücretsiz mağazadaki bir konumun nasıl yeniden kullanılabileceğini gösterir:

int *ptrInt = yeni int;
*ptrInt = 12;
cout<< *ptrInt <<'\n';
ptrInt'i sil;
cout<< *ptrInt <<'\n';
*ptrInt = 24;
cout<< *ptrInt <<'\n';

Çıktı:

12
0
24

12 değeri ilk olarak tanımlanamayan konuma atanır. Ardından konumun içeriği silinir (teoride nesne silinir). 24 değeri aynı konuma yeniden atanır.

Aşağıdaki program, bir işlev tarafından döndürülen bir tamsayı başvurusunun nasıl yeniden kullanıldığını gösterir:

#Dahil etmek
ad alanı std kullanarak;
int& fn()

int ben = 5;
int& j = ben;
dönüş j;

int ana()

int& myInt = fn();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
0 döndür;

Çıktı:

5
17

Yerel kapsamda (işlev kapsamı) bildirilen i gibi bir nesne, yerel kapsamın sonunda varlığı sona erer. Ancak, yukarıdaki fn() işlevi, i'nin referansını döndürür. Bu döndürülen başvuru aracılığıyla, main() işlevindeki myInt adı, i tarafından tanımlanan konumu 17 değeri için yeniden kullanır.

değer

Değer, değerlendirmesi bir nesnenin, bit alanının veya işlevin kimliğini belirleyen bir ifadedir. Kimlik, yukarıdaki ident gibi resmi bir kimlik veya bir değer referans adı, bir işaretçi veya bir işlevin adıdır. Çalışan aşağıdaki kodu göz önünde bulundurun:

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

++ptr; --ptr;
myInt'i döndür;

Burada myInt bir değerdir; myRef bir değer referans ifadesidir; *ptr bir değer ifadesidir çünkü sonucu ptr ile tanımlanabilir; ++ptr veya -ptr bir değer ifadesidir, çünkü sonucu ptr'nin yeni durumu (adresi) ile tanımlanabilir ve fn bir değerdir (ifade).

Aşağıdaki kod segmentini göz önünde bulundurun:

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

İkinci ifadede, 'a' konumu 2'ye sahiptir ve 'a' ile tanımlanabilir ve bir değer de öyledir. b'nin konumu 8'dir ve b ile tanımlanabilir ve bir değer de öyle. c için konumun toplamı olacaktır ve c ile tanımlanabilir ve bir değer de öyle. İkinci ifadede, 16 ve 64'ün ifadeleri veya değerleri değerlerdir (aşağıya bakın).

Aşağıdaki kod segmentini göz önünde bulundurun:

karakter dizisi[5];
sıra[0]='l', sıra[1]='o', sıra[2]='v', sıra[3]='e', sıra[4]='\0';
cout<< seq[2] <<'\n';

Çıktı 'v';

seq bir dizidir. Dizideki 'v' konumu veya benzer herhangi bir değer, i'nin bir dizin olduğu seq[i] ile tanımlanır. Yani, seq[i] ifadesi bir değer ifadesidir. Tüm dizinin tanımlayıcısı olan seq, aynı zamanda bir değerdir.

değer

Öndeğer, değerlendirmesi bir nesneyi veya bir bit alanını başlatan veya göründüğü bağlam tarafından belirtildiği gibi bir operatörün işleneninin değerini hesaplayan bir ifadedir.

açıklamada,

int myInt = 256;

256, myInt tarafından tanımlanan nesneyi başlatan bir ön değerdir (ön değer ifadesi). Bu nesneye başvurulmadı.

açıklamada,

int&& referans = 4;

4, ref tarafından başvurulan nesneyi başlatan bir ön değerdir (öndeğer ifadesi). Bu nesne resmi olarak tanımlanmadı. ref, değer referans ifadesinin veya değer referans ifadesinin bir örneğidir; bu bir isimdir, ancak resmi bir tanımlayıcı değildir.

Aşağıdaki kod segmentini göz önünde bulundurun:

int kimliği;
özdeş = 6;
int&başvuru = kimlik;

6, ident tarafından tanımlanan nesneyi başlatan bir değerdir; nesne ayrıca ref tarafından başvurulur. Burada ref, bir değer referansı değil, bir değer referansıdır.

Aşağıdaki kod segmentini göz önünde bulundurun:

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

15 ve 63'ün her biri, toplama operatörü için bir işlenen (bit olarak) üreten, kendisini hesaplayan bir sabittir. Yani, 15 veya 63 bir öndeğer ifadesidir.

Dize değişmezi dışında herhangi bir değişmez değer bir ön değerdir (i.e., bir değer ifadesi). Yani, 58 veya 58 gibi bir değişmez.53, ya da doğru ya da yanlış, bir değerdir. Bir hazır bilgi, bir nesneyi başlatmak için kullanılabilir veya bir operatör için bir işlenenin değeri olarak kendisine (bit cinsinden başka bir biçime) hesaplanabilir. Yukarıdaki kodda, değişmez 2 nesneyi başlatır, bir. Ayrıca kendisini atama operatörü için bir işlenen olarak hesaplar.

Neden bir dize değişmez değeri bir değer değil? Aşağıdaki kodu göz önünde bulundurun:

char str[] = "nefret değil sev";
cout << str <<'\n';
cout << str[5] <<'\n';

Çıktı:

nefret değil aşk
n

str tüm dizeyi tanımlar. Yani, str ifadesi, tanımladığı şey değil, bir değerdir. Dizedeki her karakter str[i] ile tanımlanabilir, burada i bir dizindir. Tanımladığı karakter değil, str[5] ifadesi bir değerdir. Dize değişmezi bir değerdir ve bir değer değildir.

Aşağıdaki ifadede, bir dizi değişmezi nesneyi başlatır, arr:

ptrInt++ veya  ptrInt-- 

Burada ptrInt, bir tamsayı konumuna yönelik bir işaretçidir. İşaret ettiği konumun nihai değeri değil, ifadenin tamamı bir değerdir (ifade). Bunun nedeni, ptrInt++ veya ptrInt- ifadesinin, aynı konumun ikinci son değerini değil, konumunun orijinal ilk değerini tanımlamasıdır. Öte yandan, -ptrInt veya -ptrInt, konumdaki ilginin tek değerini tanımladığı için bir değerdir. Buna bakmanın başka bir yolu, orijinal değerin ikinci son değeri hesaplamasıdır.

Aşağıdaki kodun ikinci ifadesinde, a veya b hala bir değer olarak kabul edilebilir:

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

Yani ikinci ifadedeki a veya b bir değerdir çünkü bir nesneyi tanımlar. Ayrıca, toplama operatörü için bir işlenenin tamsayısını hesapladığı için bir ön değerdir.

(new int) ve kurduğu yer değil, bir değerdir. Aşağıdaki ifadede, konumun dönüş adresi bir işaretçi nesnesine atanır:

int *ptrInt = yeni int

Burada *ptrInt bir değerdir, (new int) ise bir değerdir. Unutmayın, bir değer veya bir değer bir ifadedir. (new int) herhangi bir nesneyi tanımlamıyor. Adresi döndürmek, nesneyi bir adla (yukarıdaki ident gibi) tanımlamak anlamına gelmez. *ptrInt'de, ptrInt adı nesneyi gerçekten tanımlayan şeydir, bu nedenle *ptrInt bir değerdir. Öte yandan, (new int) bir değerdir, çünkü atama operatörü = için işlenen değerinin bir adresine yeni bir konum hesaplar.

x değeri

Bugün lvalue, Konum Değeri anlamına gelir; prvalue "saf" değer anlamına gelir (aşağıda değerin ne anlama geldiğine bakın). Bugün, xvalue, “geçen” değer anlamına gelir.

C++ belirtiminden alıntılanan xvalue tanımı aşağıdaki gibidir:

“Xdeğeri, kaynakları yeniden kullanılabilen bir nesneyi veya bit alanını belirten bir değerdir (genellikle ömrünün sonuna yaklaştığı için). [Örnek: Değer referanslarını içeren belirli türdeki ifadeler, dönüş tipi bir değer referansı olan bir fonksiyona yapılan çağrı veya bir değer referansı tip-son örneğine yapılan atama gibi x değerleri verir]”

Bunun anlamı, hem değerin hem de değerin süresinin dolabileceğidir. Aşağıdaki kod (yukarıdan kopyalanmıştır), *ptrInt değerinin depolanmasının (kaynağının) silindikten sonra nasıl yeniden kullanıldığını gösterir.

int *ptrInt = yeni int;
*ptrInt = 12;
cout<< *ptrInt <<'\n';
ptrInt'i sil;
cout<< *ptrInt <<'\n';
*ptrInt = 24;
cout<< *ptrInt <<'\n';

Çıktı:

12
0
24

Aşağıdaki program (yukarıdan kopyalanmıştır), bir fonksiyon tarafından döndürülen bir değer referansı olan bir tamsayı referansının depolanmasının main() fonksiyonunda nasıl yeniden kullanıldığını gösterir:

#Dahil etmek
ad alanı std kullanarak;
int& fn()

int ben = 5;
int& j = ben;
dönüş j;

int ana()

int& myInt = fn();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
0 döndür;

Çıktı:

5
17

fn() işlevindeki i gibi bir nesne kapsam dışına çıktığında, doğal olarak yok edilir. Bu durumda, i'nin depolanması hala main() işlevinde yeniden kullanılmıştır.

Yukarıdaki iki kod örneği, değerlerin depolanmasının yeniden kullanımını göstermektedir. Değerlerin (değerlerin) bir depolama yeniden kullanımına sahip olmak mümkündür (daha sonra bakınız).

xvalue ile ilgili aşağıdaki alıntı, C++ belirtiminden alınmıştır:

“Genel olarak, bu kuralın etkisi, adlandırılmış değer referanslarının değer olarak ele alınması ve nesnelere adsız değer referanslarının x değerleri olarak kabul edilmesidir. işlevlere yapılan değer referansları, adlandırılmış olsun ya da olmasın, değer olarak kabul edilir." (Daha sonra bakın).

Dolayısıyla, bir xdeğeri, kaynakları (depolama) yeniden kullanılabilen bir değer veya değerdir. xvalues, lvalues ​​ve prvalues'un kesişim kümesidir.

Bu makalede ele alınandan daha fazla xvalue var. Ancak, xvalue tek başına bütün bir makaleyi hak eder ve bu nedenle xvalue için ek spesifikasyonlar bu makalede ele alınmamıştır.

İfade Kategorisi Taksonomi Seti

C++ spesifikasyonundan başka bir alıntı:

Not: Tarihsel olarak, değerler ve değerler, bir atamanın sol ve sağ tarafında görünebildikleri için sözde idi (bu artık genel olarak doğru olmasa da); gldeğerler "genelleştirilmiş" değerlerdir, değerler "saf" değerlerdir ve xdeğerler "geçici" değerlerdir. Adlarına rağmen, bu terimler değerleri değil ifadeleri sınıflandırır. - bitiş notu”

Yani, glvalues, değerlerin ve x değerlerinin birleşim kümesidir ve rvalues, x değerlerinin ve değerlerin birleşim kümesidir. xvalues, lvalues ​​ve prvalues'un kesişim kümesidir.

Şu andan itibaren, ifade kategorisi sınıflandırması bir Venn şemasıyla aşağıdaki gibi daha iyi gösterilmiştir:

Sonuç

Değer, değerlendirmesi bir nesnenin, bit alanının veya işlevin kimliğini belirleyen bir ifadedir.

Öndeğer, değerlendirmesi bir nesneyi veya bir bit alanını başlatan veya göründüğü bağlam tarafından belirtildiği gibi bir operatörün işleneninin değerini hesaplayan bir ifadedir.

Bir xdeğeri, kaynaklarının (depolama) yeniden kullanılabileceği ek özelliği ile bir değer veya değerdir.

C++ belirtimi, bir ağaç diyagramı ile ifade kategorisi sınıflandırmasını gösterir, bu da sınıflandırmada bir hiyerarşi olduğunu gösterir. Şu an itibariyle, taksonomide hiyerarşi yoktur, bu nedenle bazı yazarlar tarafından bir Venn diyagramı kullanılır, çünkü taksonomiyi ağaç diyagramından daha iyi gösterir.

SuperTuxKart for Linux
SuperTuxKart is a great title designed to bring you the Mario Kart experience free of charge on your Linux system. It is pretty challenging and fun to...
Battle for Wesnoth Tutorial
The Battle for Wesnoth is one of the most popular open source strategy games that you can play at this time. Not only has this game been in developmen...
0 A.D. Tutorial
Out of the many strategy games out there, 0 A.D. manages to stand out as a comprehensive title and a very deep, tactical game despite being open sourc...