34 Soru: Bir işaretçi değişkeni ile C ++ 'daki referans değişken arasındaki farklar nelerdir?

tarafından oluşturulan soru Sun, Jun 17, 2018 12:00 AM

Referansların sözdizimsel şeker olduğunu biliyorum, bu yüzden kodun okunması ve yazılması daha kolay.

Fakat farklar nelerdir?


Aşağıdaki yanıtlardan ve bağlantılardan gelen özet:

  1. Bağlayıcıdan sonra bir referans atanamadığında bir işaretçiye istediğiniz sayıda yeniden atanabilir.
  2. İşaretçiler hiçbir yere işaret edemez (NULL), referans ise her zaman bir nesneye işaret eder.
  3. İşaretçilerle olduğu gibi referansın adresini alamazsınız.
  4. "Referans aritmetiği" yoktur (ancak referans ile işaretlenmiş bir nesnenin adresini alabilir ve &obj + 5'daki gibi işaretçi aritmetik yapabilirsiniz)

Bir yanılgıyı netleştirmek için:

  

C ++ standardı, bir derleyicinin nasıl düzenleyebileceğini dikte etmemek için çok dikkatli   referansları uygulayın, ancak her C ++ derleyicisi uygular   işaretçiler olarak referanslar. Yani şu şekilde bir beyan:

 
int &ri = i;
     

tamamen optimize edilmemişse , aynı miktarda depolama alanı ayırır   işaretçi olarak ve adresi yerleştirir   bu depoya i’un.

Öyleyse, bir işaretçi ve bir referans hem aynı miktarda belleği kullanır.

Genel bir kural olarak,

  • Yararlı ve kendi kendini belgeleyen arayüzler sağlamak için işlev parametrelerinde ve dönüş türlerinde referans kullanın.
  • Algoritmaları ve veri yapılarını uygulamak için işaretçiler kullanın.

İlginç okuma:

2974
  1. Bence 2. nokta "Bir işaretçinin NULL olmasına izin verilir, ancak bir başvuru yapılmaz. Yalnızca hatalı biçimlendirilmiş kod NULL başvuru oluşturabilir ve davranışı tanımlanamaz."
    2010-10-08 17: 21: 24Z
  2. İşaretçiler, başka bir nesne türüdür ve C ++ 'daki herhangi bir nesne gibi, değişken olabilirler. Öte yandan, referanslar asla nesne, sadece değişken değildir.
    2012-06-16 10: 14: 02Z
  3. Bu, uyarısız olarak derlenir: gcc'de int &x = *(int*)0;. Referans gerçekten NULL'a işaret edebilir.
    2012-08-13 09: 00: 00Z
  4. başvuru bir değişken takma adıdır
    2013-12-23 08: 53: 04Z
  5. İlk cümlenin toplam yanıltıcı olmasından hoşlanıyorum. Referansların kendi semantikleri var.
    2014-06-01 01: 58: 45Z
30 Yanıtlar                              30                         
  1. Bir işaretçi yeniden atanabilir:

     
    int x = 5;
    int y = 6;
    int *p;
    p =  &x;
    p = &y;
    *p = 10;
    assert(x == 5);
    assert(y == 10);
    

    Başvuru başlatılamıyor ve başlangıçta atanması gerekiyor:

     
    int x = 5;
    int y = 6;
    int &r = x;
    
  2. Bir işaretçi, yığında kendi hafıza adresine ve boyutuna (x86'da 4 bayt) sahipken, bir referans aynı hafıza adresini (orijinal değişkenle birlikte) paylaşırken aynı zamanda yığın üzerinde biraz yer kaplar. Bir referans orijinal değişkenle aynı adrese sahip olduğundan, aynı değişken için bir referans olarak düşünmek güvenlidir. Not: Yığın ya da öbek üzerinde bir işaretçi olabileceğine işaret eder. Referansa dala. Bu ifadedeki iddiam, bir işaretçinin yığına işaret etmesi gerektiği değildir. Bir işaretçi sadece bir hafıza adresini tutan bir değişkendir. Bu değişken yığında. Bir referans yığında kendi boşluğuna sahip olduğundan vereferans aldığı değişkenle aynı. Yığın vs yığını hakkında daha fazla bilgi. Bu, derleyicinin size söylemeyeceği bir referansın gerçek bir adresinin olduğu anlamına gelir.

     
    int x = 0;
    int &r = x;
    int *p = &x;
    int *p2 = &r;
    assert(p == p2);
    
  3. Ekstra dolaylı yönlendirme sunan işaretçilere işaretçilere işaretçileriniz olabilir. Oysa referanslar sadece bir seviyede dolaylı teklif sunmaktadır.

     
    int x = 0;
    int y = 0;
    int *p = &x;
    int *q = &y;
    int **pp = &p;
    pp = &q;//*pp = q
    **pp = 4;
    assert(y == 4);
    assert(x == 0);
    
  4. İşaretçiye doğrudan nullptr atanabilir, buna karşın başvuru yapılamaz. Yeterince sıkı çalışırsanız ve nasıl yapacağınızı biliyorsanız, nullptr referans adresini belirleyebilirsiniz. Benzer şekilde, yeterince sıkı çalışırsanız bir işaretçiye bir referansınız olabilir ve bu referans nullptr içerebilir.

     
    int *p = nullptr;
    int &r = nullptr; <--- compiling error
    int &r = *p;  <--- likely no compiling error, especially if the nullptr is hidden behind a function call, yet it refers to a non-existent int at address 0
    
  5. İşaretçiler bir dizi üzerinde yinelenebilir, bir işaretçinin işaret ettiği bir sonraki öğeye gitmek için ++ ve 5. öğeye gitmek için + 4 kullanabilirsiniz. Bu, işaretçinin işaret ettiği nesnenin boyutu ne olursa olsun.

  6. Bir işaretçinin doğrudan kullanılabildiği halde, işaretleyicinin işaret ettiği bellek konumuna erişmek için * ile değiştirilmesi gerekir. Bir sınıfa /yapıya bir işaretçi, üyelerine erişmek için ->, bir referans ise . kullanmaktadır.

  7. İşaretçi, bir bellek adresini tutan bir değişkendir. Bir referansın nasıl uygulandığına bakılmaksızın, referans referans aldığı öğeyle aynı hafıza adresine sahiptir.

  8. Referanslar bir diziye doldurulamaz, oysa işaretçiler olabilir (@litb kullanıcısı tarafından belirtilmiştir)

  9. Const referansları geçici işlere bağlanabilir. İşaretçiler olamaz (bazı dolaysızlıklar olmadan):

     
    const int &x = int(12); //legal C++
    int *y = &int(12); //illegal to dereference a temporary.
    

    Bu, const&'u argüman listelerinde vb. kullanım için daha güvenli hale getirir.

1545
2018-01-26 22: 58: 15Z
  1. ... ancak kuralsızlaştırma NULL tanımsız. Örneğin, bir referansın NULL olup olmadığını test edemezsiniz (örneğin, & ref == NULL).
    2008-09-11 22: 07: 03Z
  2. Sayı 2, değil doğru. Referanslar basitçe "aynı değişken için başka bir isim" değildir. Referanslara, işaretçilere çok benzeyen bir şekilde, sınıflarda saklanan, vb. İşlevlere geçilebilir. İşaret ettikleri değişkenlerden bağımsız olarak var olurlar.
    2008-09-12 23: 37: 54Z
  3. Brian, yığın önemli değil. Referanslar ve işaretçiler yığında yer açmak zorunda değildir. Her ikisi de öbek üzerinde tahsis edilebilir.
    2008-09-19 04: 33: 38Z
  4. Brian, bir değişkenin (bu durumda bir işaretçi veya başvuru) boşluk gerektirmesi, değil 'in yığında boşluk gerektirdiği anlamına gelir. İşaretçiler ve referanslar yalnızca öbeğe işaret etmeyebilir , öbek üzerinde aslında ayrılmış olabilir.
    2008-09-19 15: 26: 29Z
  5. başka bir önemli fark: referanslar bir diziye doldurulamıyor
    2009-02-27 21: 10: 17Z

C ++ başvurusu nedir ( C programcıları için )

Bir başvurusu , otomatik indirmeyle sabit işaretçisi (sabit işaretli bir işaretçi ile karıştırılmamalıdır!) olarak düşünülebilir, yani derleyici geçerli olacaktır. sizin için * operatörü.

Tüm referanslar boş olmayan bir değerle başlatılmalıdır, aksi halde derleme başarısız olur. Referans adresi almak mümkün değildir - adres operatörü referans verilen değerin adresini döndürür - referanslarda aritmetik yapmak da mümkün değildir.

C programcıları, C ++ referanslarını beğenmeyebilir, çünkü dolaylı olarak gerçekleştiğinde veya bir argüman işlev imzalarına bakmadan değer veya işaretçi ile iletildiğinde artık açık olmayacaktır.

C ++ programcıları, en önemsiz durumlar haricinde sürekli işaretçilerden daha güvenli olmasa da, işaretçileri kullanmaktan hoşlanmayabilir - otomatik dolaysızlıktan yoksun ve farklı bir anlamsal çağrışım taşıyorlar.

C ++ SSS ’dan aşağıdaki ifadeyi göz önünde bulundurun >:

  

Bir referans genellikle Google’da bir adres kullanılarak gerçekleştirilse de   Derleme dilinin altında, lütfen yapma bir referans olarak düşünün.   bir nesneye komik görünümlü işaretçi. Başvuru, nesnesidir. Bu   nesneye bir işaretçi veya nesnenin bir kopyası değil.   nesne.

Ancak nesne gerçekten nesne olsaydı, sarkan referanslar nasıl olabilirdi? Yönetilmeyen dillerde, referansların işaretçilerden daha 'güvenli' olması imkansızdır - genellikle kapsam sınırları boyunca değerleri güvenilir şekilde takma yolu yoktur!

Neden C ++ referanslarını faydalı görüyorum?

Bir C arka planından geliyorsa, C ++ referansları biraz saçma bir konsepte benzeyebilir, ancak mümkün olduğunda işaretçiler yerine yine de bunları kullanmalısınız: Otomatik dolaylı uygun ve uygundur. RAII ile - ancak algılanan güvenlik avantajı nedeniyle değil, idiomatik kod yazmayı daha az yaptıklarından garip.

RAII, C ++ 'nın temel kavramlarından biridir, ancak önemsiz bir şekilde kopyalama semantiği ile etkileşime girer. Nesnelerin referans olarak iletilmesi, kopyalama söz konusu olmadığından bu sorunları önler. Eğer dilde referanslar olmasaydı, bunun yerine daha hantal olan işaretçiler kullanmak zorunda kalacaksınız, bu nedenle dil tasarım prensibini ihlal ederek en iyi uygulama çözümünün alternatiflerden daha kolay olması gerekiyordu.

    
346
2015-07-07 21: 27: 53Z
  1. @ kriss: Hayır, sarkan bir referansı referans alarak otomatik bir değişken döndürerek de alabilirsiniz.
    2010-11-02 06: 14: 59Z
  2. @ kriss: Bir derleyicinin genel durumda tespit etmesi neredeyse imkansızdır. Bir sınıf üyesi değişkenine başvuru döndüren bir üye işlevi düşünün: bu güvenlidir ve derleyici tarafından yasaklanmaması gerekir. Ardından, bu sınıfın otomatik örneğine sahip olan bir arayan, bu üye işlevini çağırır ve başvuruyu döndürür. Presto: sarkan referans. Ve evet, başını belaya sokacak, Kriss: Bu benim amacım. Pek çok kişi, referanslara göre referansların bir avantajının, referansların her zaman geçerli olduğunu, ancak böyle olmadığını iddia eder.
    2010-11-02 13: 15: 28Z
  3. @ kriss: Hayır, otomatik saklama süresi nesnesine yapılan başvuru geçici bir nesneden çok farklı. Neyse, ifadenize yalnızca geçersiz bir işaretçi referansı alarak geçersiz bir başvuru alabileceğiniz için bir karşı örnek sunuyordum. Christoph haklı - referanslar işaretçilerden daha güvenli değil, yalnızca referansları kullanan bir program hala tür güvenliğini bozabilir.
    2010-11-02 15: 15: 07Z
  4. Referanslar bir tür işaretçi değildir. Bunlar varolan bir nesne için yeni bir addır.
    2011-07-20 01: 28: 00Z
  5. @ catphive: dil anlambilimine geçerseniz doğru, gerçekte uygulamaya bakarsanız doğru değil; C ++, C'den çok daha 'büyülü' bir dildir ve sihirinizi referanslardan çıkarırsanız, bir işaretçi ile sonuçlanır
    2011-07-23 09: 07: 46Z

Gerçekten bilgili olmak istiyorsanız, bir işaretçi ile yapamayacağınız bir referansla yapabileceğiniz bir şey var: geçici bir nesnenin ömrünü uzatın. C ++ 'da geçici bir nesneye const referansını bağlarsanız, o nesnenin ömrü referansın ömrü olur.

 
std::string s1 = "123";
std::string s2 = "456";

std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;

Bu örnekte s3_copy, birleştirme işleminin sonucu olan geçici nesneyi kopyalar. Oysa s3_reference özünde geçici nesne haline gelir. Bu gerçekten şu an sahip olduğu geçici bir nesneye referanstır.referans ile aynı kullanım ömrü.

Bunu const olmadan denerseniz derlemede başarısız olması gerekir. Const olmayan bir referansı geçici bir nesneye bağlayamazsınız ya da bu konuda adresini alamazsınız.

    
172
2010-10-08 16: 52: 17Z
  1. ancak bunun için kullanım durumu nedir?
    2009-10-22 14: 10: 33Z
  2. Pekala, s3_copy geçici bir işlem yapıp bunu s3_copy içine kopyalar, oysa s3_reference doğrudan geçici işlemi kullanır. O zaman gerçekten bilgili olmak için, derleyicinin kopya yapımını ilk durumda seçmesine izin verilen İade Değeri Optimizasyonuna bakmanız gerekir.
    2009-10-22 18: 14: 56Z
  3. @ digitalSurgeon: Oradaki sihir oldukça güçlü. Nesne ömrü, const & bağlanması gerçeği ile uzatılır ve yalnızca başvuru kapsam dışına çıktığında gerçek başvurulan türün yok edicisi (referans türüne kıyasla, temel olabilir) denir. Referans olduğundan, dilimler arasında dilimleme gerçekleşmez.
    2010-01-14 17: 06: 23Z
  4. C ++ 11 Güncellemesi: son cümle "geçici olmayan referans referansını geçici olarak bağlayamazsınız" yazmalı çünkü yapabileceğiniz geçici olmayan bir const olmayan değer referansını bağlayın ve aynı ömür boyu devam eden davranışa sahip.
    2013-11-10 20: 14: 26Z
  5. @ AhmadMushtaq: Bunun temel kullanımı türetilmiş sınıflardır . Herhangi bir miras yoksa, RVO /taşı inşaatı nedeniyle ucuz veya ücretsiz olacak olan değer anlamını kullanabilirsiniz. Ancak, Animal x = fast ? getHare() : getTortoise()'unuz varsa, x klasik dilimleme problemiyle karşı karşıya kalırken, Animal& x = ... doğru şekilde çalışacaktır.
    2017-11-02 11: 04: 03Z

Popüler görüşlerin aksine, NULL olan bir referans olması mümkündür.

 
int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

Verilmiş, referansla yapmak çok daha zor - ancak yönetirseniz, saçınızı bulmaya çalışırken yırtarsınız. Referanslar değil C ++ ile doğal olarak güvenlidir!

Teknik olarak bu, boş bir referans değil, geçersiz referans 'tır. C ++, null referansları diğer dillerde bulabileceğiniz bir kavram olarak desteklememektedir. Başka türlü de geçersiz referanslar var. Herhangi bir geçersiz başvuru, geçersiz bir işaretçi kullanmak gibi, tanımsız davranış 'ın hayaletini de yükseltir.

Asıl hata, NULL göstericinin başvuruda bulunmasından önce referanstır. Ancak bu durumda herhangi bir hata üretecek herhangi bir derleyiciden haberdar değilim - hata kodda daha ileri bir noktaya yayılır. Bu sorunu bu kadar sinsi yapan da bu. Çoğu zaman, bir NULL işaretleyiciyi kaldırırsanız, tam o noktada çarpışırsınız ve bunu anlamak için fazla hata ayıklama gerekmez.

Yukarıdaki örneğim kısa ve kesinti. İşte daha gerçek dünyadan bir örnek.

 
class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(i1,i2,i3,i4,i5);  // crash occurs here due to memory access violation - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

Boş bir referans almanın tek yolunun hatalı biçimlendirilmiş koddan geçtiğini ve bir kez elinizde tanımsız davranışlar elde ettiğinizi yinelemek istiyorum. Asla boş bir referans olup olmadığını kontrol etmek mantıklıdır; örneğin if(&bar==NULL)...'u deneyebilirsiniz, ancak derleyici ifadeyi varoluştan optimize edebilir! Geçerli bir referans hiçbir zaman NULL olamaz, bu nedenle derleyicinin görüşüne göre karşılaştırma her zaman yanlıştır ve if yan tümcesini ölü kod olarak kaldırmak ücretsizdir - bu tanımsız davranışın özüdür.

Beladan uzak durmanın doğru yolu, bir başvuru oluşturmak için NULL işaretleyicinin renklendirilmesinden kaçınmaktır. İşte bunu başarmanın otomatik bir yolu.

 
template<typename T>
T& deref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(deref(p));

Bu soruna daha iyi yazma becerisine sahip birinden daha eski bir görünüm için, bkz. Boş Kaynaklar Jim Hyslop ve Herb Sutter'dan.

Boş bir göstergeyi kaldırmanın tehlikelerine başka bir örnek için Raymond Chen tarafından kodu başka bir platforma taşımaya çalışırken tanımsız davranışı açığa çıkarma .

    
116
2018-01-08 22: 57: 42Z
  1. Söz konusu kod tanımsız davranış içeriyor. Teknik olarak, ayarlamak ve karşılaştırmak dışında boş bir işaretçi ile hiçbir şey yapamazsınız. Programınız tanımsız davranışlar başlattığında, büyük patrona bir demo verene kadar doğru çalışıyor gibi görünmek de dahil olmak üzere her şeyi yapabilir.
    2008-09-12 16: 00: 14Z
  2. işaretinin geçerli bir argümanı var. Bir işaretçinin NULL olabileceği ve bunun için kontrol etmeniz gereken argüman da gerçek değildir: bir fonksiyonun NULL içermemesi gerektiğini söylerseniz, arayan bunu yapmak zorundadır. Bu yüzden, arayan yoksa tanımsız davranışları çağırıyor. tıpkı markanın kötü referansla yaptığı gibi
    2009-02-27 21: 14: 41Z
  3. Açıklama hatalı. Bu kod NULL olan bir başvuru oluşturabilir veya oluşturmayabilir. Davranışı tanımsız. Mükemmel geçerli bir referans oluşturabilir. Herhangi bir referans oluşturmak başarısız olabilir.
    2011-08-20 11: 41: 33Z
  4. @ David Schwartz, eğer işlerin standarda göre çalışması gerektiğinden bahsediyor olsaydım, doğru olurdun. Ancak bu, değil hakkında konuştuğum şey - Çok popüler bir derleyici ile gerçek gözlemlenen davranışlardan bahsediyorum ve tipik derleyiciler ve CPU mimarileri hakkındaki bilgilerime dayanarak tahmin edilebileceğimden emin olabilirim oldu. Referansların işaretçilerden daha üstün olduğuna inanıyorsanız, çünkü onlar daha güvenlidir ve referansların kötü olabileceğini düşünmüyorsanız, bir gün benim gibi basit bir sorunla karşılaşacaksınız.
    2011-08-22 02: 11: 48Z
  5. Boş bir işaretçiyi reddetmek yanlıştır. Bunu yapan herhangi bir program, hatta bir referans başlatmak için bile yanlıştır. Bir işaretçiden referans başlatıyorsanız, işaretçinin geçerli olup olmadığını her zaman kontrol etmelisiniz. Bu başarılı olsa bile, referansın var olmayan bir nesneye atıfta bulunması için referanstan çıkarken herhangi bir zamanda silinebilir, değil mi? Söylediğin şey iyi şeyler. Bence asıl mesele, referansın "boş" olup olmadığının kontrol edilmesi gerekmediğini ve göstericinin en azından iddia edilmesinin gerekli olduğunu düşünüyorum.
    2017-03-22 14: 07: 22Z

Sözdizimsel şeker dışında, referans const göstericidir ( değil bir const göstericisidir). Referans değişkenini bildirirken ne anlama geldiğini belirlemelisiniz ve daha sonra değiştiremezsiniz.

Güncelleme: şimdi biraz daha düşünüyorum, önemli bir fark var.

Bir const işaretçi hedefi, adresini alarak ve bir const cast kullanarak değiştirilebilir.

Bir referansın hedefi UB’den kısa bir şekilde değiştirilemez.

Bu, derleyicinin bir referansta daha fazla optimizasyon yapmasına izin vermelidir.

    
114
2018-04-12 15: 59: 44Z
  1. Bunun şimdiye kadar en iyi cevap olduğunu düşünüyorum. Diğerleri, farklı hayvanlar gibi referanslar ve işaretçilerden bahsederler ve sonra davranışlarında nasıl farklı olduklarını ortaya koyarlar. Hiçbir şeyi daha kolay yapmaz. Referansları her zaman farklı sözdizimsel şekle sahip bir T* const olarak anladım (bu, kodunuzu çok * ve & ortadan kaldırmak için olur).
    2017-01-10 01: 34: 05Z
  2. "Bir const işaretçi hedefi, adresini alarak ve bir const cast kullanarak değiştirilebilir." Bunu yapmak tanımsız davranıştır. Bkz. stackoverflow.com/questions/25209838/… adresini ziyaret edin.
    2018-06-22 04: 51: 40Z
  3. Bir referansın referansını veya const işaretçisinin (veya herhangi bir const skalar) değerini değiştirmeye çalışmak eşitlik yasaktır. Yapabilecekleriniz: örtük dönüşümle eklenen const kalifikasyonunu kaldır: int i; int const *pci = &i; /* implicit conv to const int* */ int *pi = const_cast<int*>(pci); tamam.
    2018-06-29 16: 00: 18Z
  4. Buradaki fark UB'ye karşılık kelimenin tam anlamıyla imkansız. C ++ 'da hangi referansın işaret ettiğini değiştirmenize izin verecek bir sözdizimi yoktur.
    2018-06-29 16: 03: 01Z
  5. İmkansız değil, daha zor, sadece bu referansı modelleyen imlecin bellek alanına erişebilir ve içeriğini değiştirebilirsiniz. Bu kesinlikle yapılabilir.
    2018-11-17 21: 39: 21Z

En önemli kısmı unuttun:

işaretçilerle üye erişimi -> kullanmaktadır
referanslarla üye girişi, .

kullanır.

foo.bar açıkça foo->bar’dan üstün olduğu gibi, vi açıkça Emacs :-)

'dan üstündür     
107
2015-07-07 21: 21: 27Z
  1. @ Orion Edwards > işaretçilerle üye erişimi kullanır - > > referanslarla üye erişimi kullanır. Bu% 100 doğru değil. Bir işaretçiye bir referansınız olabilir. Bu durumda - - gt; struct Düğümü {Düğüm * sonraki; }; İlk önce düğüm *; //p, voo foo işaretçisinin referansıdır (Düğüm * & p) {p-> gt; next = ilk; } Düğüm * bar = yeni Düğüm; fan (bar); - PÇ: Değer ve değer kavramlarını biliyor musunuz?
    2008-09-12 12: 57: 12Z
  2. Akıllı İşaretçiler her ikisine de sahiptir. (akıllı işaretçi sınıfındaki yöntemler) ve - > (altta yatan tür yöntemleri).
    2014-04-09 09: 11: 06Z
  3. @ user6105 Orion Edwards ifadesi aslında% 100 doğrudur. "[]] işaretçi işaretçisinin erişim üyelerine" Bir işaretçinin hiç üyesi yok. İşaretçinin başvurduğu nesne üyelere sahiptir ve bunlara erişim, tam olarak ->'un işaretçiye olduğu gibi işaretçilere referanslar için sağladığı şeydir.
    2015-04-15 17: 37: 03Z
  4. neden . ve ->'un vi ve emacs ile ilgisi var :)
    2016-08-21 00: 45: 28Z
  5. @ artM - bir şakaydı ve anadili olmayan İngilizce konuşanlar için bir anlam ifade etmiyordu. Özür dilerim. Vi'nin emacs'tan daha iyi olup olmadığını açıklamak tamamen özneldir. Bazı insanlar vi'nin çok daha üstün olduğunu düşünüyor, diğerleri ise bunun tam tersini düşünüyor. Benzer şekilde, .'u kullanmak, ->'u kullanmaktan daha iyidir, ancak vi-emacs gibi, tamamen özneldir ve hiçbir şey ispat edemezsiniz
    2016-08-25 21: 41: 40Z

Referanslar işaretçilere çok benzer, ancak derleyicileri optimize etmek için özel olarak hazırlanmışlardır.

  • Referanslar, derleyicinin hangi değişken takma adlarını izlemesini önemli ölçüde kolaylaştıracak şekilde tasarlanmıştır. İki ana özellik çok önemlidir: "referans aritmetiği" yoktur ve referansların yeniden atanması yoktur. Bunlar, derleyicinin, derleme zamanında hangi değişkenlerin hangi takma adları referans aldığını bulmasını sağlar.
  • Referanslar aDerleyicinin kayıt altına almayı seçtiği gibi, hafıza adresleri olmayan değişkenlere gönderme yapmasına izin verilir. Yerel bir değişkenin adresini alırsanız, derleyicinin onu bir kayıt defterine koyması çok zordur.

Örnek olarak:

 
void maybeModify(int& x); // may modify x in some way

void hurtTheCompilersOptimizer(short size, int array[])
{
    // This function is designed to do something particularly troublesome
    // for optimizers. It will constantly call maybeModify on array[0] while
    // adding array[1] to array[2]..array[size-1]. There's no real reason to
    // do this, other than to demonstrate the power of references.
    for (int i = 2; i < (int)size; i++) {
        maybeModify(array[0]);
        array[i] += array[1];
    }
}

Bir optimize edici derleyici epeyce bir [0] ve [1] eriştiğimizi fark edebilir. Algoritmayı optimize etmek ister:

 
void hurtTheCompilersOptimizer(short size, int array[])
{
    // Do the same thing as above, but instead of accessing array[1]
    // all the time, access it once and store the result in a register,
    // which is much faster to do arithmetic with.
    register int a0 = a[0];
    register int a1 = a[1]; // access a[1] once
    for (int i = 2; i < (int)size; i++) {
        maybeModify(a0); // Give maybeModify a reference to a register
        array[i] += a1;  // Use the saved register value over and over
    }
    a[0] = a0; // Store the modified a[0] back into the array
}

Böyle bir optimizasyon yapmak için, çağrı sırasında hiçbir şeyin [1] dizisini değiştiremeyeceğini kanıtlaması gerekir. Bunu yapmak oldukça kolaydır. i hiçbir zaman 2'den az değildir, bu nedenle [i] dizisi asla [1] dizisine başvuruda bulunamaz. maybeModify () referans olarak a0 olarak verilir (aliasing array [0]). "Referans" aritmetiği olmadığı için, derleyici sadece belkiModify'nin asla x'in adresini alamadığını kanıtlamak zorundadır ve hiçbir şeyin diziyi değiştiremediğini kanıtlamıştır [1].

Ayrıca, gelecekteki bir çağrının a0'da geçici bir siciline sahipken bir [0] okuma /yazma yolu bulunmadığını kanıtlaması gerekir. Bu genellikle kanıtlamak için önemsizdir, çünkü çoğu durumda referansın hiçbir zaman bir sınıf örneği gibi kalıcı bir yapıda saklanmadığı açıktır.

Şimdi de işaretçilerle aynı şeyi yapın

 
void maybeModify(int* x); // May modify x in some way

void hurtTheCompilersOptimizer(short size, int array[])
{
    // Same operation, only now with pointers, making the
    // optimization trickier.
    for (int i = 2; i < (int)size; i++) {
        maybeModify(&(array[0]));
        array[i] += array[1];
    }
}

Davranış aynıdır; ancak şimdi, belki deModdify'nin diziyi [1] hiç değiştirmediğini ispatlamak çok daha zor, çünkü biz zaten bir işaretçi verdik; kedi çantadan çıktı. Şimdi çok daha zor bir kanıtı yapmalı: asla & x + 1'e yazmadığını ispatlamak için maybeModify'nin statik bir analizi. Ayrıca, [0] dizisine başvurabilecek bir göstergeden asla tasarruf etmediğini ispatlaması gerekir. aynı derecede zor.

Modern derleyiciler statik analizde daha iyi ve daha iyi hale geliyor, ancak referansları kullanmak ve referansları kullanmak her zaman güzel.

Elbette, böyle akıllı optimizasyonları engelleyen derleyiciler, gerektiğinde referansları işaretçiler haline getirecektir.

EDIT: Bu cevabı gönderdikten beş yıl sonra, referansların aynı adresleme konseptine bakmanın farklı bir yolundan farklı olduğu gerçek bir teknik fark buldum. Referanslar, geçici nesnelerin ömrünü, işaretçilerin yapamayacağı şekilde değiştirebilir.

 
F createF(int argument);

void extending()
{
    const F& ref = createF(5);
    std::cout << ref.getArgument() << std::endl;
};

Normalde createF(5) çağrısına göre oluşturulan geçici nesneler ifadenin sonunda imha edilir. Ancak, bu nesneyi ref referansına bağlayarak, C ++ bu geçici nesnenin ömrünü ref kapsam dışı kalana kadar uzatır.

    
65
2018-10-08 21: 51: 07Z
  1. Doğru, gövdenin görünür olması gerekiyor. Bununla birlikte, maybeModify'un x ile ilgili hiçbir şeyin adresini almadığını belirlemek, bir avuç işaretçi aritmetiğinin ortaya çıkmadığını kanıtlamaktan çok daha kolaydır.
    2013-09-11 04: 27: 01Z
  2. İyileştiricinin zaten "bir avuç işaretçi aritemeti oluşmadığını", başka nedenlerden dolayı kontrol ettiğini yaptığına inanıyorum.
    2013-09-11 04: 32: 58Z
  3. "Referanslar işaretçilere çok benziyor" - anlamsal olarak, uygun bağlamlarda - ancak üretilen kod bakımından, yalnızca bazı uygulamalarda ve herhangi bir tanım /gereksinim yoluyla değil. Bunu belirttiğinizi biliyorum ve pratik terimlerle yazdıklarınızdan hiçbirine katılmıyorum, ancak zaten 'referanslar işaretçiler gibi /genellikle işaretçiler' olarak uygulanmaktadır. .
    2015-10-11 17: 31: 38Z
  4. Yukarıdaki yorumların tartıştığı void maybeModify(int& x) { 1[&x]++; } satırları boyunca hatalı bir şekilde eski bir yorum olarak işaretlenmiş gibi hissediyorum.
    2015-12-03 23: 28: 49Z

Aslında, referans gerçekten bir işaretçi gibi değildir.

Bir derleyici, isimleri bir bellek adresiyle ilişkilendiren değişkenlere "referansları" tutar; Derleme sırasında herhangi bir değişken adını bir hafıza adresine çevirmek işin işidir.

Bir referans oluşturduğunuzda, derleyiciye sadece pointer değişkenine başka bir isim verdiğinizi söyleyin; bu yüzden referanslar "null" a işaret edemez, çünkü bir değişken cannÖyle ol ve ol.

İşaretçiler değişkendir; başka bir değişkenin adresini içeriyorlar veya boş olabilirler. Önemli olan bir işaretçi bir değere sahipken, bir referans sadece referans aldığı bir değişkene sahiptir.

Şimdi gerçek kodun bir açıklaması:

 
int a = 0;
int& b = a;

Burada, a’a işaret eden başka bir değişken oluşturmuyorsunuz; a değerini tutan hafıza içeriğine başka bir isim ekliyorsunuz. Bu hafızanın şimdi iki adı vardır, a ve b ve bu iki ad kullanılarak da adreslenebilir.

 
void increment(int& n)
{
    n = n + 1;
}

int a;
increment(a);

Bir işlev çağırırken, derleyici genellikle kopyalanacak argümanlar için hafıza alanları oluşturur. İşlev imzası, yaratılması gereken alanları tanımlar ve bu alanlar için kullanılması gereken adı verir. Bir parametreyi referans olarak bildirmek derleyiciye, yöntem çağrısı sırasında yeni bir bellek alanı tahsis etmek yerine giriş değişkeni bellek alanını kullanmasını söyler. İşlevinizin çağıran kapsamda bildirilen bir değişkeni doğrudan işleme koyacağını söylemek garip gelebilir, ancak derlenmiş kod yürütülürken başka bir kapsam olmadığını unutmayın; sadece düz düz hafıza var ve fonksiyon kodunuz herhangi bir değişkende değişiklik yapabilir.

Artık, derleyicinizin, bir dış değişken kullandığınızda olduğu gibi derleme sırasında referansı bilemeyebileceği bazı durumlar olabilir. Bu nedenle referans, temel kodda bir işaretçi olarak uygulanabilir veya uygulanmayabilir. Ancak size verdiğim örneklerde, büyük olasılıkla bir işaretçi ile uygulanmayacak.

    
63
2015-07-07 21: 25: 53Z
  1. Bir referans, bir değişkene değil, l değerine bir referanstır. Bu nedenle, bir göstergeye gerçek bir takma addan (derleme zamanı yapısı) çok daha yakındır. Referans verilebilecek ifadelerin örnekleri * p veya hatta * p ++
    'dır.
    2009-03-02 16: 27: 28Z
  2. Doğru, ben sadece bir referansın her zaman yeni bir göstergenin yapacağı gibi yığında yeni bir değişkene itilmeyebileceğini işaret ediyordum.
    2009-03-03 20: 36: 46Z
  3. @ VincentRobert: Bir fonksiyon işaretlendiğinde aynı işlevi görür ... eğer işlev belirtilirse, hem referans hem de işaretçi en iyi duruma getirilir. İşlev çağrısı varsa, nesnenin adresinin işleve iletilmesi gerekir.
    2012-02-13 23: 08: 55Z
  4. int * p = NULL; int &r; * p; NULL'a işaret eden referans; if (r) {} - > boOm;)
    2015-10-04 12: 37: 47Z
  5. Derleme aşamasındaki bu odaklanma, çalışma zamanında referansların pencerenin dışına çıkabileceğini hatırlatana kadar güzel görünüyor. (Sonra, referanslar genellikle işaretçiler olarak uygulanır, ancak standart bu yöntemi gerektirmez.)
    2015-10-11 17: 35: 14Z

Bir referans asla NULL olamaz.

    
38
2014-06-01 22: 37: 05Z
  1. Bir sayaç örneği için Mark Ransom'un cevabına bakınız. Bu, referanslar hakkında en sık iddia edilen efsanedir, ancak bir efsanedir. Standartlara göre elinizde olan tek şey, NULL referansınız olduğunda hemen UB'niz olduğudur. Fakat bu, “Bu araba güvenli, yoldan asla çıkamaz.” (Herhangi bir şekilde yoldan çıkarırsanız ne olabileceğinin sorumluluğunu almayız. Patlayabilir.) "
    2014-06-13 11: 36: 07Z
  2. @ cmaster: Geçerli bir programda , referans boş olamaz. Ancak bir işaretçi olabilir. Bu bir efsane değil, bu bir gerçek.
    2014-08-08 04: 42: 07Z
  3. @ Mehrdad Evet, geçerli programlar yolda kalıyor. Ancak, programınızın gerçekte ne yaptığını zorlayacak hiçbir trafik engeli yoktur. Yolun büyük kısımları aslında eksik işaretler. Bu yüzden geceleri yoldan çıkmak son derece kolaydır. Ve bunun olabileceğini bildiğiniz bu tür hataları ayıklamak için çok önemlidir: boş bir referans, tıpkı bir boş gösterici gibi, programınızı çökmeden önce çoğalabilir. Ve 49410 gibi bir kodunuz varsa, bu segfaults. Referansların boş olabileceğini bilmiyorsanız, boşluğu başlangıç ​​noktasına kadar izleyemezsiniz.
    2014-12-29 10: 43: 30Z
  4. int * p = NULL; int &r; * p; NULL'a işaret eden referans; if (r) {} - > boOm;) -
    2015-10-04 12: 43: 33Z
  5. @ sree void Foo::bar() { virtual_baz(); } tanımsız bir davranış. Bu noktada, "NULL'a işaret eden bir referansınız" yok, artık hakkında hiç bir sebep olmayacak bir programınız var .
    2017-03-28 18: 46: 25Z

Hem referanslar hem de işaretçiler, başka bir değere dolaylı olarak erişmek için kullanılırken, referanslar ve işaretçiler arasında iki önemli fark vardır. Birincisi, referansın her zaman bir nesneye gönderme yaptığıdır: Bir referansı başlatmadan tanımlamak bir hatadır. Atama davranışı ikinci önemli farktır: Bir referansa atanmak referansın bağlı olduğu nesneyi değiştirir; başvuruyu başka bir nesneye yeniden bağlamadı. Başlatıldıktan sonra, referans her zaman aynı temel nesneye karşılık gelir.

Bu iki program parçasını göz önünde bulundurun. İlk önce, bir işaretçiyi diğerine atarız:

 int &r=*p;

Atamadan sonra, ival, pi tarafından adreslenen nesne değişmeden kalır. Atama, pi'nin değerini değiştirerek farklı bir nesneye işaret eder. Şimdi iki referans atanan benzer bir program düşünün:

 
int ival = 1024, ival2 = 2048;
int *pi = &ival, *pi2 = &ival2;
pi = pi2;    // pi now points to ival2

Bu atama referansın kendisini değil, ri tarafından referans verilen değeri ival olarak değiştirir. Ödevden sonra, iki referans hala orijinal nesnelerini ifade eder ve bu nesnelerin değeri şimdi de aynıdır.

    
33
2015-10-23 23: 16: 52Z
  1. "bir referans her zaman bir nesneye atıfta bulunur" sadece tamamen yanlış
    2017-07-21 18: 29: 56Z

    Bilgisayar dillerini soyut ve hatta akademik bir şekilde öğrenmeye aşina değilseniz, ezoterik görünebilecek anlamsal bir fark vardır.

    En üst düzeyde, referanslar fikri şeffaf "takma" olmalarıdır. Bilgisayarınızın çalışmasını sağlamak için bir adres kullanabilir, ancak bunun için endişelenmeniz gerekmiyor: onları varolan bir nesne için "başka bir ad" olarak düşünmeniz gerekiyor ve sözdizimi bunu yansıtıyor. İşaretçilerden daha katı olduklarından derleyiciniz sarkan bir referans oluşturmak üzereyken, sarkan bir işaretçi oluşturmak üzereyken olduğundan daha güvenilir bir şekilde sizi uyarabilir.

    Bunun ötesinde, elbette işaretçilerle referanslar arasında bazı pratik farklılıklar vardır. Bunları kullanmak için kullanılan sözdizimi açıkça farklıdır ve referansları "yeniden sıralayamaz", hiçlik referansları veya referanslara işaretçileriniz olamaz.

        
    28
    2014-10-29 17: 17: 23Z

    Bir referans, başka bir değişken için bir takma isimdir, oysa bir işaretçi bir değişkenin hafıza adresini tutar. Referanslar genellikle işlev parametreleri olarak kullanılır, böylece iletilen nesne kopya değil nesnenin kendisidir.

     
    int &ri = ival, &ri2 = ival2;
    ri = ri2;    // assigns ival2 to ival
    
        
    22
    2013-01-01 17: 45: 46Z

    Ne kadar yer kapladığı önemli değildir, çünkü ne kadar yer kaplayacağına ilişkin herhangi bir yan etki (kod yürütmeden) göremezsiniz.

    Diğer yandan, referanslar ve işaretçiler arasındaki en büyük farklardan biri, referans referansları kapsamına girinceye kadar başvuru referansları için atanan geçici yayınların canlı yayınlanmasıdır.

    Örneğin:

     
        void fun(int &a, int &b); // A common usage of references.
        int a = 0;
        int &b = a; // b is an alias for a. Not so common to use. 
    

    yazdıracak:

     
    class scope_test
    {
    public:
        ~scope_test() { printf("scope_test done!\n"); }
    };
    
    ...
    
    {
        const scope_test &test= scope_test();
        printf("in scope\n");
    }
    

    Bu, ScopeGuard'ın çalışmasını sağlayan dil mekanizmasıdır.

        
    18
    2012-07-03 14: 41: 02Z
    1. Bir referansın adresini alamazsınız, ancak bu fiziksel olarak yer kaplamadıkları anlamına gelmez. İyileştirmeleri engellemek için kesinlikle yapabilirler.
      2011-04-24 16: 27: 32Z
    2. Etkisi olmasına rağmen, "Yığıntaki bir başvuru hiç yer almaz" açık bir şekilde yanlıştır.
      2011-04-25 23: 09: 47Z
    3. @ Tomalak, bu da derleyiciye bağlıdır. Ama evet, bunun biraz kafa karıştırıcı olduğunu söylemek. Sanırım bunu kaldırmanın daha az kafa karıştırıcı olacağını düşünüyorum.
      2011-04-26 21: 52: 17Z
    4. Herhangi bir özel durumda olabilir veya olmayabilir. Bu nedenle, kategorik bir iddia yanlış olduğu için “değildir”. Benim dediğim de o. :) [Standardın bu konuda ne dediğini hatırlayamıyorum; Referans üyelerin kuralları genel olarak "referanslar yer alabilir" kuralını getirebilir, ancak standardın kopyasını burada yanımda kumsalda alamıyorum: D]
      2011-04-26 22: 22: 05Z

    Bu, eğiticisine dayanmaktadır. Yazılanlar onu daha açık hale getirir:

     
    in scope
    scope_test done!
    

    Basitçe bunu hatırlamak,

     
    >>> The address that locates a variable within memory is
        what we call a reference to that variable. (5th paragraph at page 63)
    
    >>> The variable that stores the reference to another
        variable is what we call a pointer. (3rd paragraph at page 64)
    

    Dahası, neredeyse tüm işaretçi kılavuzlarına atıfta bulunabileceğimiz gibi, işaretçi, işaretçiyi bir diziye benzer yapan işaretçi aritmetik ile desteklenen bir nesnedir.

    Aşağıdaki ifadeye bakın,

     
    >>> reference stands for memory location
    >>> pointer is a reference container (Maybe because we will use it for
    several times, it is better to remember that reference.)
    
    int Tom(0);
    int & alias_Tom = Tom;
    
    , alias_Tom (alias of a variable ile farklı olan typedef ile farklı) alias of a type olarak anlaşılabilir. Ayrıca böyle bir ifadenin terminolojisini unutmak da sorun değil, Tom referansı oluşturmaktır.     
    18
    2015-07-07 21: 35: 57Z
    1. Ve bir sınıfın bir başvuru değişkeni varsa, başlatma listesinde bir nullptr veya geçerli bir nesne ile başlatılmalıdır.
      2015-06-15 17: 32: 10Z
    2. Bu cevaptaki ifadeler, gerçek kullanım için çok kafa karıştırıcıdır. Ayrıca, @Misgevolution, Tom ile referans başlatmak için okuyuculara şiddetle tavsiye ediyor musunuz? Gerçekten bu konunun herhangi bir bölümünü okudunuz mu, veya ...?
      2015-10-11 17: 27: 40Z
    3. Söylediğim aptalca şey için üzgünüm. O zamana kadar mahrum kalmış olmalıyım. 'nullptr ile başlat' tamamen yanlıştır.
      2015-10-11 18: 09: 41Z

    Bir referans, hafızaya verilen başka bir isim değildir. Kullanımda otomatik olarak referanstan kaldırılan değişmez bir işaretçidir. Temelde aşağı kaynar:

     nullptr

    Dahili olarak olur

     
    int& j = i;
    
        
    18
    2017-01-1001: 46: 19Z
    1. C ++ Standardının söylediği şey bu değildir ve derleyicinin referanslarınızla cevabınızla açıklanan şekilde uygulanması gerekmez.
      2013-02-26 05: 22: 44Z
    2. @ jogojapan: Bir C ++ derleyicisinin bir başvuruyu uygulaması için geçerli olan herhangi bir yol,
      int* const j = &i;
      
      işaretçisini uygulamak için de geçerli bir yoldur. Bu esneklik referans ile işaretçi arasında bir fark olduğunu kanıtlamaz.
      2015-08-26 23: 00: 21Z
    3. @ BenVoigt Herhangi birinin geçerli bir uygulamasının diğerinin de geçerli bir uygulaması olduğu doğru olabilir, ancak bu, tanımlarının açık bir şekilde takip edilmediğidir. bu iki kavram. Tanımlardan iyi bir cevap başlamış olacaktı ve ikisi hakkındaki iddianın nihayetinde aynı olduğu doğrulandı. Bu cevap diğer cevapların bazıları hakkında bir tür yorum gibi görünüyor.
      2015-08-26 23: 41: 55Z
    4. Bir referans , bir nesneye verilen başka bir addır . Derleyicinin, herhangi bir uygulamaya sahip olmasına izin verilir, farkı söyleyemediğiniz sürece, bu "as-if" kuralı olarak bilinir. Buradaki önemli kısım, farkı söyleyemeyeceğiniz. Bir işaretçinin depolama alanı olmadığını keşfederseniz, derleyici yanlıştır. Bir referansın depolama alanı olmadığını keşfederseniz, derleyici yine de uygundur.
      2017-09-06 14: 52: 31Z

    Bunlardan birine ihtiyacım olmadıkça referansları kullanırım:

    • Boş işaretçiler bir sentinel değeri, genellikle ucuz bir yoldur işlev aşırı yüklenmesini veya bir bool.

    • İşaretçi üzerinde aritmetik işlem yapabilirsiniz. Örneğin, const

    15
    2015-07-07 21: 22: 16Z
    1. p += offset;'un referans olarak ilan edildiği &r + offset yazabilirsiniz
      2017-02-23 05: 13: 46Z

    Bir işaretçi referansı C ++ 'da mümkündür, ancak bunun tersi mümkün değildir, bir referans işaretçisi mümkün değildir. Bir işaretçiye yapılan bir referans, işaretçiyi değiştirmek için daha temiz bir sözdizimi sağlar. Şu örneğe bakın:

     r

    Ve yukarıdaki programın C versiyonunu düşünün. C'de işaretçi için işaretçi kullanmanız gerekir (çoklu dolaylı) ve bu karışıklığa yol açar ve program karmaşık görünebilir.

     
    #include<iostream>
    using namespace std;
    
    void swap(char * &str1, char * &str2)
    {
      char *temp = str1;
      str1 = str2;
      str2 = temp;
    }
    
    int main()
    {
      char *str1 = "Hi";
      char *str2 = "Hello";
      swap(str1, str2);
      cout<<"str1 is "<<str1<<endl;
      cout<<"str2 is "<<str2<<endl;
      return 0;
    }
    

    İşaretçiye başvuru hakkında daha fazla bilgi için aşağıdakileri ziyaret edin:

    Dediğim gibi, referans için bir işaretçi mümkün değildir. Aşağıdaki programı deneyin:

     
    #include<stdio.h>
    /* Swaps strings by swapping pointers */
    void swap1(char **str1_ptr, char **str2_ptr)
    {
      char *temp = *str1_ptr;
      *str1_ptr = *str2_ptr;
      *str2_ptr = temp;
    }
    
    int main()
    {
      char *str1 = "Hi";
      char *str2 = "Hello";
      swap1(&str1, &str2);
      printf("str1 is %s, str2 is %s", str1, str2);
      return 0;
    }
    
        
    15
    2015-07-08 09: 06: 24Z

    İşaretçilerle, kimsenin bahsetmediğini görmediğim referanslar arasında temel bir fark vardır: referanslar, fonksiyon argümanlarında referans-referans anlambilimini sağlar. İşaretçiler, ilk başta görünmese de, şunları yapmazlar: yalnızca değer-değer anlambilimi sağlarlar. Bu, bu makalede çok güzel bir şekilde tarif edilmiştir.

    Selamlar, &Sons, rzej

        
    14
    2012-02-06 08: 59: 29Z
    1. Referanslar ve işaretçiler hem tutamaçlardır. Her ikisi de size nesnenizin referans tarafından iletildiği, ancak tanıtıcısının kopyalandığı bir anlam ifade ediyor. Fark yok. (Sözlükte arama anahtarı gibi tutamaçlara sahip olmanın başka yolları da vardır)
      2013-11-07 17: 16: 16Z
    2. Ben de böyle düşünürdüm. Ancak neden böyle olmadığını anlatan bağlantılı makaleye bakın.
      2013-11-12 09: 08: 25Z
    3. @ Andrzj: Yorumumdaki tek cümlenin çok uzun bir sürümü: Tutamaç kopyalandı.
      2013-11-12 15: 10: 26Z
    4. Bu "Tanıtıcı kopyalandı" hakkında daha fazla açıklamaya ihtiyacım var. Bazı temel fikirleri anlıyorum ama fiziksel olarak referansın ve işaretçinin değişkenin bellek konumunu işaret ettiğini düşünüyorum. Takma ad, değer değişkenini depolar ve değişkenin değeri değişiklik veya başka bir şey olduğu için günceller mi? Acemiyim ve lütfen bunu aptalca bir soru olarak işaretlemeyin.
      2013-12-11 23: 13: 44Z
    5. @ Andrzej Yanlış. Her iki durumda da, by-pass değeri oluşuyor. Referans değere ve işaretçi değere göre iletilir. Aksi söylenmesi yenileri karıştırır.
      2014-04-27 09: 28: 30Z

    Karışıklık ekleme riski altında bazı girdiler yazmak istiyorum, çoğunlukla derleyicinin referansları nasıl uyguladığına bağlı olduğuna eminim, ancak gcc durumunda bir referansın yalnızca bir değişkeni gösterebileceği fikri Yığında aslında doğru değil, örneğin bunu al:

     
    #include <iostream>
    using namespace std;
    
    int main()
    {
       int x = 10;
       int *ptr = &x;
       int &*ptr1 = ptr;
    }
    

    Bunu veren çıktı:

     
    #include <iostream>
    int main(int argc, char** argv) {
        // Create a string on the heap
        std::string *str_ptr = new std::string("THIS IS A STRING");
        // Dereference the string on the heap, and assign it to the reference
        std::string &str_ref = *str_ptr;
        // Not even a compiler warning! At least with gcc
        // Now lets try to print it's value!
        std::cout << str_ref << std::endl;
        // It works! Now lets print and compare actual memory addresses
        std::cout << str_ptr << " : " << &str_ref << std::endl;
        // Exactly the same, now remember to free the memory on the heap
        delete str_ptr;
    }
    

    Bellek adreslerinin bile tamamen aynı olduğunu fark ederseniz, referans başarıyla öbek üzerindeki bir değişkeni işaret eder! Şimdi gerçekten garip olmak istiyorsanız, bu da işe yarıyor:

     
    THIS IS A STRING
    0xbb2070 : 0xbb2070
    

    Bunu veren çıktı:

     
    int main(int argc, char** argv) {
        // In the actual new declaration let immediately de-reference and assign it to the reference
        std::string &str_ref = *(new std::string("THIS IS A STRING"));
        // Once again, it works! (at least in gcc)
        std::cout << str_ref;
        // Once again it prints fine, however we have no pointer to the heap allocation, right? So how do we free the space we just ignorantly created?
        delete &str_ref;
        /*And, it works, because we are taking the memory address that the reference is
        storing, and deleting it, which is all a pointer is doing, just we have to specify
        the address with '&' whereas a pointer does that implicitly, this is sort of like
        calling delete &(*str_ptr); (which also compiles and runs fine).*/
    }
    

    Bu nedenle referans, başlık altında bir işaretçidir, ikisi de sadece adresin işaret ettiği bir bellek adresi saklıyorlar, std :: cout < < str_ref; Gördükten sonra delete & str_ref? Tabii ki gayet iyi bir şekilde derleniyor, ancak çalışma zamanında bir segmentasyon hatasına neden oluyor çünkü artık geçerli bir değişkeni işaret etmiyor, temelde hala mevcut olan (kapsam dışına düşene kadar) kırık bir referansımız var.

    Başka bir deyişle, referans, işaretçi mekaniğinin soyutlanmış olan bir işaretçiden başka bir şey değildir, kullanımı daha güvenli ve daha kolay hale getirir (yanlışlıkla imleç matematiği yok, karıştırma yok. ), yukarıdaki örneklerim gibi saçma sapan olmadığınızı varsayarak;)

    Şimdi, bir derleyicinin referansları nasıl işlediğine bakmaksızın, her zaman , başlık altında bir tür işaretçiye sahip olacaktır, çünkü bir referansın başvurması gerekir Beklenildiği gibi çalışması için belirli bir hafıza adresindeki belirli bir değişkene, bunun üstesinden gelmek mümkün değildir (bu nedenle 'referans' terimi).

    Referanslarla hatırlanması gereken tek önemli kural, beyan sırasında tanımlanmaları gerektiğidir (bir başlıktaki bir referans hariç, bu durumda yapıcıda, nesneden sonra tanımlanmalıdır) içerdiği tanımlamak için çok geç inşa edilmiştir).

    Unutmayın, yukarıdaki örneklerim tam olarak bu; referansın ne olduğunu gösteren örnekler, bir referansı asla bu şekilde kullanmak istemezsiniz! Bir referansın doğru kullanımı için zaten kafanın üzerinde çiviyi vuran çok sayıda cevap var.

        
    13
    2014-10-14 21: 38: 00Z

    Başka bir fark, geçersiz bir türdeki işaretçileriniz olabilir (ve bu herhangi bir şeye işaretçi anlamına gelir) ancak boşluğa yapılan referanslar yasaktır.

     
    THIS IS A STRING
    

    Bu farktan gerçekten çok mutlu olduğumu söyleyemem. Adrese sahip herhangi bir şeye anlam referansı ve referanslar için aynı davranışa izin verilmesini çok tercih ederim. Referansları kullanarak memcpy gibi bazı C kütüphanesi işlevlerinin eşdeğerini tanımlamaya izin verir.

        
    12
    2015-04-29 15: 00: 54Z

    Doğrudan cevap

    C ++ 'da referans nedir? Nesne türü olmayan belirli bir tür örneği.

    C ++ 'da işaretçi nedir? Nesne türü olan belirli bir tür örneği.

    Nesne türünün ISO C ++ tanımından :

      

    Bir nesnesi türü, bir referans türü değil, cv olmayan, işlev türü olmayan (muhtemelen cv niteliğinde) bir türdür. > geçersiz.

    Bilmek önemli olabilir, nesne tipi C ++ 'da evren tipi bir üst seviye kategoridir. Referans aynı zamanda üst seviye bir kategoridir. Ancak işaretçi değil.

    İşaretçiler ve referanslar birlikte belirtildi bileşik türü ğlamında em> int a; void * p = &a; // ok void & p = a; // forbidden + & vs. &&.) Bu bağlamda, "bu bağlamda" C "ile benzer bir dil çizilmesi. biraz makul. (Bildirgelerin sözdiziminin çok sözdizimsel ifadesini boşa harcadığını, hem insan kullanıcıları hem de uygulamaları sinir bozucu hale getirdiğini savunacağım. Böylece, hepsi yerleşik yeni bir dil tasarımında. Bu, PL tasarımında tamamen farklı bir konudur.)

    Aksi halde, işaretçilerin birlikte referanslarla belirli tür türleri olarak nitelendirilebilmesi önemsizdir. Onlar sadece sözdizimi benzerliğinin yanı sıra çok az ortak özelliği paylaşırlar, bu yüzden çoğu durumda bunları bir araya getirmeye gerek yoktur.

    Yukarıdaki açıklamaların sadece "işaretçiler" ve "referanslar" olarak verildiğini not edin. Örnekleriyle ilgili bazı ilgi çekici sorular var (değişkenler gibi). Ayrıca çok fazla yanlış anlama geldi.

    Üst düzey kategorilerin farklılıkları, işaretçilere doğrudan bağlı olmayan birçok somut farklılığı zaten gösterebilir:

    • Nesne türleri, üst düzey * kalifiye olabilir. Referanslar olamaz.
    • Nesne türlerinin değişkenliği, soyut makineye ilişkin semantics uyarınca depolama alanı kullanır. Referanslar depolamaya gerek duymaz (ayrıntılar için aşağıdaki yanlış anlamalarla ilgili bölüme bakın).
    • ...

    Referanslarla ilgili birkaç özel kural:

    • Bileşik bildiriciler referanslarda daha kısıtlayıcıdır.
    • Referanslar daraltabilir .
      • Şablon parametresi indirimi sırasındaki referans çökmesine dayanan cv parametrelerinde ("yönlendirme referansları" olarak) özel kurallar "mükemmel iletme" parametrelerin.
    • Referansların başlatılmasında özel kuralları var. Referans tipi olarak bildirilen değişkenin ömrü, uzatma yoluyla sıradan nesnelerden farklı olabilir.
      • BTW, &&'u içeren başlatma gibi birkaç diğer bağlam, benzer referans ömrü uzatma kurallarını izler. Bir başka solucan kutusudur.
    • ...

    Kavram yanılgıları

    Sözdizimsel şeker

      

    Referansların sözdizimsel şeker olduğunu biliyorum, bu yüzden kodun okunması ve yazılması daha kolay.

    Teknik olarak, bu tamamen yanlış. Referanslar, C ++ 'daki herhangi bir başka özelliğin sözdizimsel şekeri değildir, çünkü herhangi bir anlamsal fark olmadan başka özellikler tarafından tam olarak değiştirilemezler.

    (Benzer şekilde, lambda ifadesi ler, C ++ 'daki diğer özelliklerin sözdizimsel şekeridir çünkü yakalanan değişkenlerin bildirim sırası ;önemli olabilir çünkü bu tür değişkenlerin başlangıç ​​sırası önemli olabilir.)

    C ++ bu katı anlamda sadece birkaç çeşit sözdizimsel şekere sahiptir. Bir örnek (C'den devralınan) yerleşik (aşırı yüklenmemiş) operatör std::initializer_list olup, tam olarak, [] ve ikili * ikili operatörlerinin yerleşik operatör üzerinden belirli kombinasyon biçimlerinin tam anlamsal özelliklerine sahip olması .

    Depolama

      

    Öyleyse, bir işaretçi ve bir referans hem aynı miktarda belleği kullanır.

    Yukarıdaki ifade sadece yanlış. Bu tür yanlış anlamaları önlemek için, bunun yerine ISO C ++ kurallarına bakın:

    [intro.object] /1 'den:

      

    ... Bir nesne, inşaat süresi boyunca, ömrü boyunca ve imha süresince bir depolama bölgesini işgal eder. ...

    [dcl.ref] /4 'den:

      

    Bir referansın depolama gerektirip gerektirmediği belirtilmez.

    Bunların anlamsal özellikler olduğunu unutmayın.

    Edimbilim

    İşaretçiler, dil tasarımı anlamında referanslarla bir araya getirilebilecek kadar nitelikli olmasalar da, örneğin bazı parametrelerde seçimler yaparken, örneğin diğer bazı bağlamlarda seçim yapmayı tartışılmaz kılan bazı argümanlar var. türleri.

    Ama bu bütün hikaye değil. Demek istediğim, işaretçilerden daha fazla şey var, dikkate almanız gereken referanslar vs.

    Bu kadar spesifik seçimlere bağlı kalmak zorunda kalmazsanız, çoğu durumda cevap kısadır: işaretçiler kullanma zorunluluğunuz yoktur, bu yüzden istemezsiniz . İşaretçiler genellikle yeterince kötüdür, çünkü beklemeyeceğiniz çok fazla şey ima ederler ve kodun korunabilirliğini ve (hatta) taşınabilirliğini zayıflatan çok fazla gizli varsayımlara güvenirler. Gereksiz yere işaretçilere güvenmek kesinlikle kötü bir stildir ve modern C ++ anlamında kullanılmaması gerekir. Amacınızı yeniden gözden geçirin ve nihayet göreceksiniz. > çoğu durumda.

    • Bazen dil kuralları açıkça kullanılacak belirli türler gerektirir. Bu özellikleri kullanmak istiyorsanız kurallara uyun.
      • Kopya yapıcılar, 1. parametre türü olarak belirli cv - + referans türü gerektirir. (Ve genellikle & nitelikli olmalıdır.)
      • Move yapıcıları, 1. parametre türü olarak belirli cv - const referans türü gerektirir. (Genelde niteleyici olmamalıdır.)
      • Operatörlerin belirli aşırı yüklemeleri referans veya referans olmayan tipler gerektirir. Örneğin:
        • Özel üye işlevleri olarak aşırı yüklenmiş &&, kopyala /taşı yapıcılarının 1. parametresine benzer referans türleri gerektirir.
        • operator= Soneki, ++ numaralı kukla'yı gerektirir.
        • ...
    • Eğer parola değerinin (yani referans olmayan türlerin kullanılması) yeterli olduğunu biliyorsanız, özellikle C ++ 17 zorunlu kopya seçimini destekleyen bir uygulama kullanırken doğrudan kullanın. ( Uyarı : Bununla birlikte, gereklilikle ilgili olarak ayrıntılı bir şekilde gerekçe, çok karmaşık olabilir. >.)
    • Bazı tutamaçları sahiplikle çalıştırmak istiyorsanız, ham işaretçiler yerine, int ve unique_ptr gibi akıllı işaretçiler kullanın (veya eğer kendi başlarına opak olmalarını talep ediyorsanız bile homebrew olanlar ile).
    • Bir aralıktaki bazı yinelemeler yapıyorsanız, ham işaretçilerin daha iyisini yapacağı konusunda ikna olmadıkça, ham işaretçiler yerine, yineleyiciler (veya henüz standart kitaplık tarafından sağlanmayan bazı aralıklar) kullanın (örneğin, daha az başlık bağımlılığı için) çok özel durumlarda.
    • Parola değerinin yeterli olduğunu biliyorsanız ve açık bir şekilde okunabilir anlambilimi istiyorsanız, ham işaretçiler yerine shared_ptr gibi bir sarıcı kullanın.
    • Geçiş değerinin yukarıdaki nedenlerden dolayı ideal olmadığını biliyorsanız ve boş anlambilimsel anlam istemiyorsanız, {lvalue, rvalue, forwarding} -references komutunu kullanın.
    • Geleneksel işaretçi gibi anlambilgisi istemeseniz bile, Kütüphane Temel TS'de std::optional gibi, genellikle daha uygun bir şeyler vardır.

    Tek istisnalar geçerli dilde çözülemez:

    • Yukarıdaki akıllı işaretçileri uyguladığınızda, ham işaretçilerle uğraşmanız gerekebilir.
    • Özel dil birlikte çalışma yordamları, observer_ptr gibi işaretçiler gerektirir. (Ancak, cv - operator new, normal nesne işaretçilerine kıyasla hala oldukça farklı ve daha güvenlidir, çünkü siz istekli olmadığınız sürece, beklenmeyen işaretçi aritmetik kurallarını ekarte eder.GNU’lar gibi void*’da bazı uyumlu olmayan uzantıların kullanılması.)
    • İşlev işaretçileri, yakalama olmadan lambda ifadelerinden dönüştürülebilir, işlev referansları yapamaz. Bu gibi durumlar için, genel olmayan kodda işlev işaretçileri kullanmanız gerekir, hatta kasıtlı olarak null değerlerini istemezsiniz.

    Yani pratikte cevap çok açık: şüpheniz olduğunda, işaretçilerden kaçının . İşaretçileri yalnızca başka hiçbir şeyin daha uygun olmamasının çok açık nedenleri olduğunda kullanmanız gerekir. Yukarıda belirtilen birkaç istisnai durum dışında, bu seçimler neredeyse her zaman yalnızca tamamen C ++ 'ya özgü değildir (ancak dile göre uygulamaya özgü olması muhtemeldir). Bu gibi durumlar olabilir:

    • Eski stil (C) API’lere sunmanız gerekir.
    • Belirli C ++ uygulamalarının ABI gereksinimlerini karşılamanız gerekir.
    • Çalışma zamanında, belirli uygulamaların varsayımlarına dayanan farklı dil uygulamalarıyla (çeşitli derlemeler, dil çalışma zamanı ve bazı üst düzey istemci dillerinin FFI'si dahil) birlikte çalışmanız gerekir.
    • Bazı aşırı durumlarda çevirinin verimliliğini (derleme ve bağlantı) geliştirmek zorundasınız.
    • Bazı aşırı durumlarda sembol şişmesinden kaçınmanız gerekir.

    Dil tarafsızlığı uyarıları

    Soruyu bazı Google arama sonuçlarından görmeye gelirseniz (C ++ 'a özgü değil) , bunun yanlış yer olması çok muhtemeldir.

    C ++ 'daki referanslar, esas olarak birinci sınıf olmadığı için oldukça "tuhaf" tır: nesneler veya atıfta bulunulan işlevler olarak değerlendirilirler bu nedenle üye erişim operatörü , belirtilen nesnenin türünden bağımsız olarak. Diğer diller referanslarında benzer kısıtlamalara sahip olabilir veya olmayabilir.

    C ++ 'daki referanslar büyük olasılıkla farklı dillerdeki anlamı korumaz. Örneğin, genel olarak yapılan referanslar, C ++ 'da olduğu gibi değerler üzerindeki boş olmayan özellikleri ima etmez, bu nedenle bu varsayımlar diğer bazı dillerde çalışmayabilir (ve karşı örnekleri kolayca bulabilirsin, örneğin, Java, C #, ...).

    Genel olarak farklı programlama dillerindeki referanslar arasında hala bazı ortak özellikler olabilir, ancak bunu SO'daki diğer bazı sorular için bırakalım.

    (Bir not: soru, ALGOL 68 - PL /I .)

        
    12
    2019-03-01 12: 43: 18Z

    Referansların başka bir ilginç kullanımı, kullanıcı tanımlı bir tür için varsayılan bir argüman sağlamaktır:

     void*

    Varsayılan lezzet, referansların 'const referansını geçici olarak bağlama' özelliğini kullanır.

        
    10
    2008-09-12 17: 59: 56Z

    Ayrıca, sıralı bir işleve parametre olan bir başvuru, bir işaretçiden farklı olarak ele alınabilir.

     
    class UDT
    {
    public:
       UDT() : val_d(33) {};
       UDT(int val) : val_d(val) {};
       virtual ~UDT() {};
    private:
       int val_d;
    };
    
    class UDT_Derived : public UDT
    {
    public:
       UDT_Derived() : UDT() {};
       virtual ~UDT_Derived() {};
    };
    
    class Behavior
    {
    public:
       Behavior(
          const UDT &udt = UDT()
       )  {};
    };
    
    int main()
    {
       Behavior b; // take default
    
       UDT u(88);
       Behavior c(u);
    
       UDT_Derived ud;
       Behavior d(ud);
    
       return 1;
    }
    

    İşaretçi sürümünün bir satırını satırlarken çoğu derleyici aslında belleğe yazmaya zorlar (adresi açıkça alıyoruz). Bununla birlikte, referansı daha uygun bir kayıt defterinde bırakacaklar.

    Elbette, işaretçi ve başvuru satır içi olmayan işlevler için aynı kodu oluşturur ve işlev tarafından değiştirilip döndürülmezse, referanstan ziyade değere göre gerçekleri iletmek her zaman daha iyidir.

        
    10
    2009-10-15 01: 57: 37Z

    Bu program, sorunun cevabını anlamada yardımcı olabilir. Bu, basit bir "j" referans programı ve "x" değişkenine işaret eden "ptr" işaretçisidir.

     
    void increment(int *ptrint) { (*ptrint)++; }
    void increment(int &refint) { refint++; }
    void incptrtest()
    {
        int testptr=0;
        increment(&testptr);
    }
    void increftest()
    {
        int testref=0;
        increment(testref);
    }
    

    Programı çalıştırın ve çıktıya bir bakın, anlayacaksınız.

    Ayrıca, 10 dakika ayırın ve bu videoyu izleyin: https://www.youtube.com/watch?v=rlJrrGV0iOg

        
    10
    2013-03-15 03: 11: 50Z

    Burada ele alınmayan başka bir nokta olduğunu hissediyorum.

    İşaretçilerden farklı olarak, başvurular başvuruda bulundukları nesneye sözdizimsel olarak eşdeğerdir , yani bir nesneye uygulanabilecek herhangi bir işlem referans için çalışır ve aynı sözdizimiyle Tabii ki başlangıç).

    Bu yüzeysel görünse de, bu özelliğin bazı C ++ özellikleri için çok önemli olduğuna inanıyorum, örneğin:

    • Şablonlar . Şablon parametreleri ördek tipinde olduğundan, bir türün sözdizimsel özellikleri önemli, bu yüzden aynı şablon hem

      #include<iostream>
      
      using namespace std;
      
      int main()
      {
      int *ptr=0, x=9; // pointer and variable declaration
      ptr=&x; // pointer to variable "x"
      int & j=x; // reference declaration; reference to variable "x"
      
      cout << "x=" << x << endl;
      
      cout << "&x=" << &x << endl;
      
      cout << "j=" << j << endl;
      
      cout << "&j=" << &j << endl;
      
      cout << "*ptr=" << *ptr << endl;
      
      cout << "ptr=" << ptr << endl;
      
      cout << "&ptr=" << &ptr << endl;
          getch();
      }
      
      hem de T ile kullanılabilir.
      (veya T&, hala örtük bir oyuncu kadrosuna dayanmaktadır. - std::reference_wrapper<T>’a) ​​
      Hem T&'u hem de T&'u kapsayan şablonlar daha yaygındır.
    • SolDeğerler . T&& ifadesini göz önünde bulundurun Referans olmadan sadece c-string'ler için işe yarar (str[0] = 'X';). Karakteri referansa göre döndürmek, kullanıcı tanımlı sınıfların aynı notaya sahip olmasını sağlar.

    • Kurucuları kopyala . Sözdizimsel olarak, yapıcıları kopyalamak için nesneler iletmek anlamlıdır, nesnelere işaretçiler değil. Ancak, bir kopya kurucusunun değerine göre bir nesneyi almasının hiçbir yolu yoktur - bu aynı kopya kurucuyu özyinelemeli bir çağrıya yol açar. Bu referansları burada tek seçenek olarak bırakır.

    • Operatör aşırı yükleniyor . Referanslarla, bir operatör çağrısına dolaylı olarak giriş yapmak mümkündür - örneğin, aynı ek gösterimi koruyarak char* str. Bu ayrıca normal aşırı yüklü fonksiyonlar için de geçerlidir.

    Bu noktalar, C ++ 'nın önemli bir bölümünü ve standart kütüphaneyi güçlendirir, bu nedenle bu referansların oldukça büyük bir özelliğidir.

        
    9
    2017-07-06 19: 48: 46Z
    1. " zımni cast " bir alçı, bir sözdizimi yapısıdır, dilbilgisinde bulunur; oyuncu seçimi her zaman açıktır
      2017-10-22 23: 58: 15Z

    Belki bazı metaforlar yardımcı olabilir; Masaüstü ekran alanınız bağlamında -

    • Bir referans, gerçek bir pencere belirtmenizi gerektirir.
    • Bir işaretçi, ekranda o pencerenin sıfır veya daha fazla örneğini içereceğinden emin olduğunuz bir alan parçasının konumunu gerektirir.
    8
    2014-12-27 13: 00: 18Z

    İşaretçiler ve referanslar arasında teknik olmayan çok önemli bir fark var: İşaretçi tarafından bir işleve iletilen bir argüman, const olmayan başvuru tarafından işleve iletilen bir argümandan çok daha belirgindir. Örneğin:

     operator+(const T& a, const T& b)

    C’ye dönersek,

    void fn1(std::string s);
    void fn2(const std::string& s);
    void fn3(std::string& s);
    void fn4(std::string* s);
    
    void bar() {
        std::string x;
        fn1(x);  // Cannot modify x
        fn2(x);  // Cannot modify x (without const_cast)
        fn3(x);  // CAN modify x!
        fn4(&x); // Can modify x (but is obvious about it)
    }
    
    ’a benzeyen bir çağrı yalnızca değere göre aktarılabilir, bu nedenle kesinlikle fn(x)’u değiştiremez; Bir argümanı değiştirmek için x imleci geçmeniz gerekir. Eğer bir argüman fn(&x)'dan önce gelmediyse, değiştirilmeyeceğini biliyordun. (Dönüşüm, &, değiştirilmiş demektir, doğru değildi, çünkü bazen salt okunur büyük yapıları & işaretçi ile geçirmeniz gerekirdi.)

    Bazıları, kodu okurken bu kadar faydalı bir özellik olduğunu, işlev const'u beklemese bile işaretçi parametrelerinin her zaman const referansları yerine değiştirilebilir parametreler için kullanılması gerektiğini savunuyor. Yani, bu insanlar yukarıdaki nullptr gibi fonksiyon imzalarına izin verilmemesi gerektiğini savunuyorlar. Google’ın C ++ stil kuralları buna bir örnektir.

        
    8
    2018-06-25 18: 58: 31Z

    İşaretçi ve başvuru arasındaki fark

    Bir işaretçi 0 olarak başlatılabilir ve bir referans değil. Aslında, başvuru aynı zamanda bir nesneye de atıfta bulunmalıdır, ancak bir işaretçi boş gösterici olabilir:

     fn3()

    Ancak

    int* p = 0;
    
    ve int& p = 0;’a sahip olamayız.

    Doğru bir şekilde yapabilmek için, ilk önce bir nesneyi ilan etmeli ve tanımlamalıyız, o zaman bu nesneye referans verebiliriz, bu nedenle önceki kodun doğru uygulanması şöyle olacaktır:

     int& p=5 ;

    Bir diğer önemli nokta, göstericinin bildirimini başlatma olmadan yapabiliriz, ancak referans durumunda her zaman değişken veya nesneye referans olması gereken hiçbir şey yapılamaz. Bununla birlikte, bir işaretçinin bu şekilde kullanımı risklidir, bu nedenle genellikle işaretçinin gerçekte bir şeye işaret edip etmediğini kontrol ederiz. Bir referans olması durumunda, böyle bir kontrol gerekli değildir, çünkü zaten bir bildirim sırasında bir nesneye atıfta bulunmanın zorunlu olduğunu biliyoruz.

    Başka bir fark, işaretçinin başka bir nesneyi gösterebilmesidir, ancak başvuru her zaman aynı nesneye atıfta bulunur, bu örneği ele alalım:

     
    Int x = 0;
    Int y = 5;
    Int& p = x;
    Int& p1 = y;
    

    Başka bir nokta: STL şablonu gibi bir şablona sahip olduğumuzda, bu tür bir sınıf şablonu, []:

    işlecini kullanarak kolay okuma veya yeni değer atamak için her zaman bir gösterici değil referans gösterecektir.  
    Int a = 6, b = 5;
    Int& rf = a;
    
    Cout << rf << endl; // The result we will get is 6, because rf is referencing to the value of a.
    
    rf = b;
    cout << a << endl; // The result will be 5 because the value of b now will be stored into the address of a so the former value of a will be erased
    
        
    6
    2017-02-08 13: 43: 19Z
    1. Hala
      Std ::vector<int>v(10); // Initialize a vector with 10 elements
      V[5] = 5; // Writing the value 5 into the 6 element of our vector, so if the returned type of operator [] was a pointer and not a reference we should write this *v[5]=5, by making a reference we overwrite the element by using the assignment "="
      
      olabilir.
      2017-01-06 14: 24: 37Z
    2. Bu durumda referans yalnızca okunacak şekilde kullanılacaktır, "const_cast" yalnızca işaretçi referansı kabul etmediği için "const_cast" kullanarak bile bu const referansını değiştiremiyoruz.
      2017-01-06 14: 37: 44Z
    3. const_cast referanslarla iyi çalışıyor: coliru.stacked-crooked.com/a/eebb454ab2cfd570
      2017-01-06 16: 52: 27Z
    4. bir referans almamak için bir başvuru yapıyorsunuz; const int & i =; const_cast < int H (i) grubudur; Referansa yeni değer yazmayı ve yeni değeri atamayı mümkün kılmak için referansın kabiliyetini atmaya çalışıyorum ama bu mümkün değil. lütfen odaklanın !!
      2017-01-06 19: 38: 23Z

    Fark, sabit olmayan imleç değişkeninin (bir imleçle sabitlenmeyecek şekilde karıştırılmaması) program yürütme sırasında bir süre içinde değiştirilebileceği, referansların yalnızca ilk kullanıma koyulduktan sonra ayarlayın (bu nedenle bunları yalnızca oluşturucu başlatıcı listesinde ayarlayabilir, ancak bir şekilde değil). Çok eski bazı kitaplarda okuduğum gibi operatörlerin aşırı yüklenmesine destek vermek için temel olarak referanslar tanıtıldı. Bu iş parçasında belirtildiği gibi - işaretçi 0 olarak veya istediğiniz değerde ayarlanabilir. 0 (NULL, nullptr), işaretçinin hiçbir şey olmadan başlatıldığı anlamına gelir. Boş göstericiyi geçersiz kılmak bir hatadır. Ancak aslında işaretçi, doğru hafıza konumuna işaret etmeyen bir değer içerebilir. Sırasıyla, referanslar, her zaman doğru türde değer verdiğinizden dolayı, kullanıcının başvuruda bulunamayacağı bir şeye başvuru başlatmasına izin vermemeye çalışır. Referans değişkeni yanlış bir bellek konumuna başlatmak için birçok yol olsa da, bunu daha ayrıntılı olarak incelemeyin. Makine seviyesinde, hem işaretçi hem de referans eşit şekilde çalışır - işaretçiler aracılığıyla. Diyelim ki temel referanslarda sözdizimsel şeker var. değer referansları bundan farklıdır - bunlar doğal olarak yığın /yığın nesneleridir.

        
    5
    2016-04-24 13: 27: 53Z

    Daima bu kuralı:

      

    T & yerine T * tercih edin; "bağımsız değişken yok" geçerli bir seçenek olduğunda

        
    2
    2017-10-19 11: 50: 17Z
    1. const int& i = 0'a izin vermek yerine işaretçi almayan aşırı yüklenmiş işlevleri kullanmak veya terminal nesneleri kullanmak, nullptr'a argüman olarak izin vermek yerine, daha iyi bir çözüm olabilir.
      2017-12-19 09: 01: 34Z
    2. @ Daha temizleyici Muhtemelen daha temizdir, ancak bazen işaretçileri hızlı bir şekilde geçmeniz gerekir ve işaretçinin boş olup olmamasına aldırış etmemeniz gereken durumlar olabilir.
      2017-12-19 10: 02: 06Z
    nullptr
kaynak yerleştirildi İşte