hata: 'int' türündeki bir r değerinden 'int &' türündeki const olmayan başvurunun geçersiz başlatılması


87

Yanlış form:

int &z = 12;

Doğru form:

int y;
int &r = y;

Soru :
İlk kod neden yanlış? Başlıktaki hatanın" anlamı "nedir?


5
Geçiciler sabit olmayan referanslara bağlanamaz. int (12) bu durumda geçicidir.
Prasoon Saurav

@PrasoonSaurav Geçici 12 ile ne demek istiyorsun? Burada kavram eksikliği (benim açımdan :))
Aquarius_Girl

2
Bu kısıtlamanın kesin bir teknik nedeni olmadığını unutmayın . Geçicilere değişken referanslara izin vermek için uygulanması da aynı derecede kolay olurdu . Yasaklamak , C ++ ' nın bir tasarım kararıdır , çünkü böyle bir yapı, gerçek yardımcı programa göre istemeden suistimal edilme riski çok daha fazla olan kötü bir tasarım olacaktır. ( Böyle bir şeye sadece bir kez
uydurulmuş

@KerrekSB muhtemelen rvalue nesnesine bağlanma başvurusu için en yaygın ihtiyaç(ostringstream() << "x=" << x).str()
wonderguy

@curiousguy: Evet, paylaştığım bağlantının içeriği bu.
Kerrek SB

Yanıtlar:


133

C ++ 03 3.10 / 1 diyor ki: "Her ifade ya bir ldeğer ya da bir değerdir." Değerliliğe karşı değerliliğin nesnelerin değil ifadelerin bir özelliği olduğunu hatırlamak önemlidir.

Lvalues, tek bir ifadenin ötesinde kalan nesneleri adlandırır. Örneğin obj, *ptr, ptr[index]ve++x tüm Sol taraf vardır.

R değerleri, içinde yaşadıkları tam ifadenin sonunda buharlaşan geçicilerdir ("noktalı virgülle"). Örneğin 1729, x + y, std::string("meow")vex++ tüm SağDeğerler bulunmaktadır.

Operatörün adresi, "işlenenin bir değer" olmasını gerektirir. bir ifadenin adresini alabilseydik, ifade bir ldeğerdir, aksi takdirde bir r değeri olur.

 &obj; //  valid
 &12;  //invalid

2
" eğer bir ifadenin adresini alabilseydik, ifade bir ldeğerdir, aksi takdirde bir r değeridir. " Keşke C ++ bu kadar basit olsaydı! (ama nüans burada gerçekten alakalı değildir) "R değerleri geçicidir" geçici ne? nesneler?
wonderguy

2
@curiousguyRvalues, içinde yaşadıkları tam ifadenin sonunda kaybolan geçicidir. İfadenin neden int & = 12;geçersiz olduğunu basitçe cevaplamak için , standart bir dize değişmezinin bir ldeğer olduğunu, diğer değişmezlerin rdeğerler olduğunu söyler.
BruceAdi

@curiousguy: Evet. R değerleri geçici nesnelerdir , ancak tüm r değerleri geçici nesneler değildir; bazıları nesne bile değildir.
Nawaz

" Örneğin, 1729, x + y, std :: string (" miyav ") ve x ++ 'nın tümü rdeğerlerdir. " Ancak std::string("meow")türde bir nesne oluşturur std::stringve bu nesneyi belirten, 1729yan etkisi olmayan ve değer veren bir değer verir 1729 bir tür değeri olarak int.
curiousguy

1
@curiousguy: İfade "Lvalues name objects that persist beyond a single expression."% 100 doğru bir ifadedir. Aksine, örneğiniz (const int &)1yanlıştır çünkü "adlandırılmış" bir nesne DEĞİLDİR.
Nawaz

53
int &z = 12;

Sağ tarafta int, integral değişmez değerinden geçici bir tür nesnesi oluşturulur 12, ancak geçici, const olmayan bir referansa bağlanamaz. Dolayısıyla hata. Şununla aynıdır:

int &z = int(12); //still same error

Neden geçici oluşturulur? Bir referansın bellekteki bir nesneye atıfta bulunması gerektiğinden ve bir nesnenin var olması için önce yaratılması gerekir. Nesne adsız olduğu için geçici nesnedir. Adı yok. Bu açıklamadan, ikinci davanın neden iyi olduğu hemen hemen netleşti.

Geçici bir nesne const referansına bağlanabilir, yani bunu yapabilirsiniz:

const int &z = 12; //ok

C ++ 11 ve Rvalue Referansı:

Tamlık adına, C ++ 11'in geçici nesneye bağlanabilen rvalue-reference'i tanıttığını eklemek isterim. Yani C ++ 11'de şunu yazabilirsiniz:

int && z = 12; //C+11 only 

Bir &&intead olduğunu unutmayın &. Ayrıca const, zbağlanan nesne değişmez- tamamlayıcıdan oluşturulmuş geçici bir nesne olsa bile, artık buna gerek olmadığını unutmayın 12.

C ++ 11 kişiye yana rvalue referans , int&artık bundan böyle adlandırılır lvalue referans .


10

12referans verilen verilerden farklı olarak değiştirilemeyen bir derleme zamanı sabitidir int&. Ne yapabilirsiniz do

const int& z = 12;

2
@curiousguy, tutarlı olun, "Bunların C ++ kuralları olduğunu anlamalısınız. Varlar ve herhangi bir gerekçeye gerek yok" dediniz (ilk baskıdan bahsetmeye gerek yok). Kendinize göre olanı vermemenizden şikayetinizi nasıl yorumlamalıyım?
Michael Krelin - Hacker

2
@ MichaelKrelin-hacker: Teknik olarak hayır, bir değere (veya zaman sabitine) bir referansı bağlayamazsınız (veya zaman sabitini derleyemezsiniz ), standart gerçekte ne olduğu konusunda oldukça açıktır: Aksi takdirde, geçici bir "cv1 T1" türü oluşturulur ve referans olmayan kopya başlatma (8.5) kuralları kullanılarak başlatıcı ifadesinden başlatılır. Referans daha sonra geçiciye bağlanır. Yani sözdizimine izin verilir, ancak anlambilim sabite bir referansı bağlamayı değil, dolaylı olarak yaratılan geçiciye bağlamayı içerir.
David Rodríguez - dribeas

1
@curiousguy: Dilin kuralları tasarımın bir parçasıdır ve çoğu zaman dilin neden böyle tasarlandığına dair gerekçeler vardır. Bu özel durumda, C'de olduğu gibi bir değerin adresini almanıza izin verilmez (bir değeri yoktur) veya bir referans bağlayamazsınız. Şimdi void f( vector<int> const & ), değiştirilmeyecek bir vektörü iletmek için deyimsel olan bir işlevi düşünün . Şimdi sorun, bunun f( vector<int>(5) )yanlış olması ve kullanıcının void f( vector<int> v ) { f(v); }önemsiz olan farklı bir aşırı yükleme sağlamak zorunda kalmasıdır.
David Rodríguez - dribeas

1
... şimdi bu, dilin kullanıcıları için acı verici olacağından, tasarımcılar derleyicinin sizin için eşdeğer işlemi gerçekleştireceğine karar verdi, çağrıda f( vector<int>(5) )derleyici bir geçici oluşturur ve ardından referansı geçici olarak bağlar ve benzer şekilde 5doğrudan'dan örtük bir dönüştürme varsa . Bu, derleyicinin işlev için tek bir imza oluşturmasına ve işlevin tek bir kullanıcı tarafından uygulanmasına olanak tanır. Bundan sonra, tutarlılık için sabit referansların geri kalan kullanımları için benzer davranış tanımlanır.
David Rodríguez - dribeas

1
@ MichaelKrelin-hacker: başvurular nesnelerin takma adlarıdır ve bir değer nesne değildir. Bağlama bağlı olarak, referanslar yalnızca takma ad olabilir , derleyici referansı kaldırır ve yalnızca tanımlayıcıyı orijinal nesnenin ne anlama geldiğini ifade etmek için T const & r = *ptr;kullanır ( rişlevde daha sonra herhangi bir kullanım ile değiştirilebilir *ptrve rçalışma zamanında var olması gerekmez) veya takma ad verdiği nesnenin adresi korunarak uygulanması gerekebilir (bir referansı bir nesnenin bir üyesi olarak saklamayı düşünün) - ki bu, otomatik başvurulan bir işaretçi olarak uygulanır.
David Rodríguez - dribeas

4

Const olmayan ve const referans bağlama farklı kuralları izler

C ++ dilinin kuralları şunlardır:

  • değişmez bir sayıdan ( 12) oluşan bir ifade bir "rvalue"
  • rvalue ile const olmayan bir referans oluşturulmasına izin verilmez: int &ri = 12;kötü biçimlidir
  • bir rvalue ile bir const başvurusu yaratılmasına izin verilir: bu durumda, derleyici tarafından isimsiz bir nesne yaratılır; bu nesne referansın kendisi var olduğu sürece devam edecektir.

Bunların C ++ kuralları olduğunu anlamalısınız. Onlar sadece.

Biraz farklı kurallarla farklı bir dil, örneğin C ++ 'icat etmek kolaydır. C ++ 'da, bir rvalue ile const olmayan bir referans oluşturulmasına izin verilir. Burada tutarsız veya imkansız hiçbir şey yok.

Ancak, programcının amaçladığını alamayacağı bazı riskli kodlara izin verirdi ve C ++ tasarımcıları haklı olarak bu riski önlemeye karar verirdi.


0

Referanslar, değişebilecek şeylere (değerlere) yönelik "gizli işaretçilerdir" (boş olmayan). Onları sabit olarak tanımlayamazsınız. "Değişken" bir şey olmalı.

DÜZENLE::

Hakkında düşünüyorum

int &x = y;

neredeyse eşdeğer

int* __px = &y;
#define x (*__px)

burada __pxyeni bir isim ve #define xeserler sadece xreferans beyanını içeren blok içinde .


1
Referans ise neden yapabilirsiniz const:)
Michael Krelin - hacker

Ancak posterin örneği değildiconst
Basile Starynkevitch

Evet, ifadelerinizin "referanslar değişebilen şeylere işaret ettiğini" kastetmiştim - bu, maliyet dışı referanslarla ilgili.
Michael Krelin - hacker

" Gizli işaretçileri 'Başvurular olan' " yanlış " değiştirebilir şeyler " yanlış " (SolDeğerler) değiştirebilirsiniz şeyler. " Yanlış
curiousguy

@Loki: Daha fazlasını açıklayabilir misin?
Basile Starynkevitch
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.