2013-05-26 22 views
6

Neden değerleri const by-value-yakalanan, ancak yakalanan bazında referans nesneleri değildir: Bana göreLambda: Neden yakalanan değerler değerlerini oluşturuyor, ancak referans değerleri yakalamıyor?

int a; 

auto compile_error = [=]() 
{ 
    a = 1; 
} 
auto compiles_ok = [&]() 
{ 
    a = 1; 
} 

bu mantıksız görünüyor ama standart gibi görünüyor? Özellikle yakalanan bir değerin istenmeyen modifikasyonu can sıkıcı bir böcek olabileceğinden, ancak sonuçların lambda kapsamıyla sınırlı olduğu, ancak referansla yakalanan nesnelerin istenmeyen modifikasyonlarının çoğunlukla daha ciddi etkilere yol açacağı ihtimalleri yüksektir.

Peki neden varsayılan başına const referans olarak yakalayamaz? Ya da en azından [const &] ve [&] destekleyin? Bu tasarımın nedenleri nelerdir?

olarak muhtemelen değeri tarafından yakalanan std :: cref sarılmış const referanslar kullanmak gerekiyor geçici çözüm? da const olan

+0

Bir referansın yakalanmasındaki önemli nokta, onu değiştirmektir. Bir değeri değiştirmek için * hayır * nedeni vardır - bu anlamsızdır. – Elazar

+3

Referanslar değişmezdir ve bağlandıktan sonra asla değiştirilemez. Yani bir anlamda lambda ifadeleri, buradaki dilin geri kalanıyla tutarlıdır. Lambda ifadeleri için 'mutable' anlamını öğrenmek isteyebilirsiniz. –

+0

@Elazar: Geçici olarak değerler değiştirilebilir, ancak yine de önerdiğiniz gibi bir değeri değiştirmek sorun değildir, başvurulan bir nesneyi değiştirmek ise istenmeyen (hata) olabilecek diğer kapsamları gerçekten etkiler. – valoh

cevap

1

Yakalanan referanslar. Eğer nereye bir referans noktalarını değiştirmenize olanak sağlar dilinde hiçbir sözdizimi yoktur - Ya da daha doğrusu, referanslar hep örtük const bulunmaktadır. a = 1;, a başvuru kaynağı referans olarak değil, referansın başvurduğu şeyi değiştirerek başvuruyor.

siz "const referans" hakkında konuşmak

, sana karıştı düşünüyorum. "Const int başvurusu" ( const int &) hakkında konuşuyorsunuz. Burada "const" referansın kendisi değil, referansın işaret ettiği şeyi ifade eder. İşaretçilerle benzer: "int göstergesine" ( const int *), işaretçinin kendisi const değil - istediğiniz türden bir değişkene atayabilirsiniz. Gerçek bir "const işaretçisi" int *const olur. Burada, bu tip bir şeye atayamazsınız; ancak int noktalarını değiştirebilirsiniz. Bu nedenle, işaretçi veya başvuru için "const", işaret ettiği şey için "const" dan ayrıdır. Ayrıca "const int'ye const const" da sahip olabilirsiniz: const int *const. lambda'lar opsiyonel gerekli referansları olan yalnızca bir kod parçası vardır:

+1

Tabii ki, referansların her zaman her zaman aynı nesneye atıfta bulunduğunu biliyorum. const değerine referans olarak referans (sabit yanıltıcı konu). Çok amaçlı yazma (lambdas sistemi) bağlamında lambda kullanıldığında, istenmeyen yazılar kolaylıkla yarış koşullarına yol açar. Const doğruluk C++ kavramı ile Imo diğer dillere (C# gibi) göre bir avantajı vardır, ama lambdas bağlamında biraz dağınık görünmektedir. Ve değişmiş nesnelerin açık bir şekilde işaretlendiği, const lambdalarının bulunmasının kolay bir yolunun nedenini bilmek isterim. – valoh

0

Benim mantık şöyle diyor. Aslında bir şeyi kopyalamanız gerektiğinde (ki bu genellikle bir paylaşımlı_ptr kopyalama gibi bellek yönetimi amacıyla gerçekleşir), lambda'nın kendi haline sahip olmasını gerçekten istemezsiniz. Bu oldukça sıra dışı bir durum.

Ben sadece 2 Aşağıdaki seçenekler "doğru" sen "dolaştır" böylece

  • , bazı yerel değişkenleri kullanarak bazı kodlar içine alın yukarıdaki gibi
  • aynı, sadece bellek yönetimini eklemek hissediyorlar Belki de kodun eşzamansız olarak veya bir şeyini yürütmek isteyebilirsiniz, çünkü oluşturma kapsamı ortadan kalkar.

Ama bir lambda "değişken" olduğunda, yani, const olmayan değerleri yakalar, bu aslında kendi devlet destekler demektir. Anlamı, bir lambda her arama yaptığınızda, gerçek kapanış, ancak yine de benim kitabımda karşı bir tür sezgisel olan iç durum dayanmayan, farklı bir sonuç verebilir lambdaşların fonksiyonel dillerden kaynaklandığı düşünülürse.Ancak, C++, C++ olarak, bu sınırlamayı atlatmanın, biraz garip hale getirerek, sadece garip bir şey yaptığınızın farkında olduğunuzdan emin olmanın bir yolunu verir.

Umarım bu nedenleri sizlerle.

+0

Yakalama değerlerinin neden oluşturulduğunu ve tamamen varsayılan olarak bunu almanın iyi bir fikir olduğuna tamamen katılıyorum. Ama hala elde edemediğim eksiklik, referans olarak ele alınışında eksik kalıcılığı desteklemesi, özellikle de çok dişli ortamlarda sağlam lamba kullanımını önlediği için -> non-const == olası yarış durumu bu kadar iyi olmamalı. Bunu gerçekten ne zaman denemek. – valoh

+0

Oh. Bence bu bir tür durum. Bir lambda IMO, oldukları gibi yerel değişkenlerle ilgilenir. Her bir kenar davası için özel sözdizimi eklediyseniz, en azından bir canavarca dürtüyle ... ... ve daha * çok * canavarca biriyle sonuçlanırdınız.Tahmin edebileceğiniz gibi, işlevsel olarak, burada sahip olmak istediğiniz şeyi elde etmek, değişkeni sadece bir referansla eşleştirerek ve sonra bu takma adı ele geçirmek mümkündür. –

+0

Belki de çok fazla bekliyorum :-) Ve aslında sanırım orijinal sorumu çok yanlış anladım. Şimdi, referans olarak ele almak için const-by-value'in const olmasının geçerli olmasının aynı nedenlerini tartışacağım. Ve bir const nesnesini değiştirmek için, her zaman modifiye edilmiş olanı gerçekten açık hale getiren const cast'e sahip olursunuz. En azından [const &]() {} desteği çok fazla gelmiyor. Mevcut haliyle, yakalama referansının const işlenmesi, biraz özensiz görünmektedir ve temiz ve sağlam bir kullanımı desteklememektedir. – valoh

7

Bir işaretçiyi değere göre yakaladığınızı varsayalım. İşaretçinin kendisi const, ancak işaret ettiği nesneye erişim değildir.

int* const p; 

Benzer şey atfen olur: operator()() üzerine

struct lambda { 
    int* p; 
    lambda(int* p_) : p(p_) {} 
    void operator()() const { ++*p; } 
}; 

const olarak ilan etmek p eşdeğer kullanımını yapar:

int i = 0; 
int* p = &i; 
auto l = [=]{ ++*p; }; 
l(); 
std::cout << i << std::endl; // outputs 1 

Bu lamda eşdeğerdir. Referansın kendisi "const" (referanslar tekrar edilemediği için alıntılarda), ancak başvurduğu nesneye erişim değildir.