C ++ 11 aralık tabanlı döngü: değere göre değer veya get'e başvuru


215

Aralık tabanlı döngülerin bazı örneklerini okurken iki ana yol önerirler 1 , 2 , 3 , 4

std::vector<MyClass> vec;

for (auto &x : vec)
{
  // x is a reference to an item of vec
  // We can change vec's items by changing x 
}

veya

for (auto x : vec)
{
  // Value of x is copied from an item of vec
  // We can not change vec's items by changing x
}

İyi.

vecÖğeleri değiştirmemize gerek olmadığında , IMO, Örnekler ikinci sürümü (değere göre) kullanmanızı önerir. Neden constreferanslar bir şey önermiyoruz (En azından ben doğrudan bir öneri bulamadık):

for (auto const &x : vec) // <-- see const keyword
{
  // x is a reference to an const item of vec
  // We can not change vec's items by changing x 
}

Daha iyi değil mi? Bu yinelemede, her yinelemede gereksiz bir kopyadan kaçınmıyor constmu?

Yanıtlar:


390

Öğeleri değiştirmek ve kopya yapmaktan kaçınmak istemiyorsanız auto const &, doğru seçimdir:

for (auto const &x : vec)

Kim kullanmanızı önerirse auto &yanlış. Boşver onları.

İşte özet:

  • auto xKopyalarla ne zaman çalışmak istediğinizi seçin .
  • auto &xOrijinal öğelerle ne zaman çalışmak istediğinizi seçin ve bunları değiştirebilirsiniz.
  • auto const &xOrijinal öğelerle ne zaman çalışmak istediğinizi seçin ve bunları değiştirmeyeceksiniz.

21
Harika cevap için teşekkürler. Sanırım const auto &xüçüncü tercihinize eşdeğer olduğuna dikkat edilmelidir .
smg

7
@mloskot: Eşdeğer. (ve "ama aynı sözdizimi" ile ne demek istiyorsun ? Sözdizimi gözle görülür şekilde farklıdır.)
Nawaz

14
Eksik: auto&&Gereksiz bir kopya yapmak istemediğinizde ve değiştirip değiştirmediğinizi umursamadığınızda ve sadece çalışmak istediğinizde.
Yakk - Adam Nevraumont

4
Yalnızca int / double gibi temel türlerle çalışıyorsanız, referans ayrım kopyalar için geçerli mi?

4
@racarate: Genel hız hakkında yorum yapamam ve bence kimse önce bunu profillemeden yapamaz. Açıkçası, seçimimi hıza değil, kodun netliğine dayandırmayacağım. Değişmezlik istersem, constkesinlikle kullanırdım . Ancak, auto const &ya olacak ya da auto const çok az fark var. auto const &Sadece daha tutarlı olmayı seçerdim .
Nawaz

23

Bir std::vector<int>veya varsa std::vector<double>, o zaman bir veya a kopyalamak ucuz olduğu için auto(değer kopyalı) kullanmak iyi olur :const auto&intdouble

for (auto x : vec)
    ....

Ancak std::vector<MyClass>, MyClassönemsiz olmayan bir kopya semantiği (örneğin std::string, bazı karmaşık özel sınıflar vb.) Varsa , const auto&derin kopyaları önlemek için kullanmanızı öneririm :

for (const auto & x : vec)
    ....

3

vecÖğeleri değiştirmemize gerek olmadığında , Örnekler ilk sürümü kullanmanızı önerir.

Sonra yanlış bir öneri verirler.

Neden referans veren bir şey önermiyorlar?

Çünkü yanlış bir öneri veriyorlar :-) Bahsettiğiniz doğru. Yalnızca bir nesneyi gözlemlemek istiyorsanız , bir kopya oluşturmanıza gerek yoktur ve bu nesneye constbaşvurulmasına gerek yoktur .

DÜZENLE:

Bağladığınız referansların bir dizi intdeğer veya başka bir temel veri türü üzerinden yineleme örnekleri sağladığını görüyorum . Bu durumda, intbir kopyalamanın pahalı olmaması nedeniyle, bir kopya oluşturmak temel olarak bir gözlem yapmaya (daha etkili değilse) eşittir const &.

Bununla birlikte, genel olarak kullanıcı tanımlı tipler için durum böyle değildir. UDT'lerin kopyalanması pahalı olabilir ve bir kopya oluşturmak için bir nedeniniz yoksa (alınan nesneyi orijinalini değiştirmeden değiştirmek gibi), a kullanılması tercih edilir const &.


1

Burada tam tersine döneceğim ve auto const &döngü için bir aralıkta gerek olmadığını söyleyeceğim . Aşağıdaki işlevin saçma olduğunu düşünüyorsanız (amacında değil, yazılı olarak) söyle:

long long SafePop(std::vector<uint32_t>& v)
{
    auto const& cv = v;
    long long n = -1;
    if (!cv.empty())
    {
        n = cv.back();
        v.pop_back();
    }
    return n;
}

Burada yazar, vv değiştirmeyen tüm işlemler için kullanmak için bir const referansı yarattı . Bu aptalca, bence, ve auto const &döngü için bir döngü içinde bir aralıkta değişken olarak kullanmak için aynı argüman yapılabilir auto &.


3
@BenjaminLindley: Öyleyse const_iteratorbir for döngüsü içinde de tartışacağınızı çıkarabilir miyim ? Orijinal öğeleri bir konteynırdan tekrarlarken bir kaptan değiştirmemenizi nasıl sağlarsınız?
Nawaz

2
@BenjaminLindley: Kodunuz neden olmadan derlenmiyor const_iterator? Tahmin edeyim, yinelediğin konteyner öyle const. Peki neden constbaşlayalım? constNeyi sağlamak için kullandığınız bir yer ?
Nawaz

8
Nesne yapmanın constavantajı, sınıfta private/ kullanmanın avantajları gibidir protected. Başka hatalardan kaçınır.
Mesud

2
@BenjaminLindley: Oh, bunu göz ardı ettim. Sonra bu durumda, uygulama da aptalca. Ancak bu işlev değişmezse v, uygulama IMO olur. Ve döngü, yinelediği nesneleri asla değiştirmezse, bana başvurmak doğru görünüyor const. Ne demek istediğini anlıyorum. Benimki döngü, fonksiyonun yaptığı gibi bir kod birimini temsil ediyor ve bu birim içinde değeri değiştirmek için herhangi bir talimat yok. Bu nedenle, tüm birimi constbir constüye işlevinde yaptığınız gibi "etiketleyebilirsiniz" .
Andy Prowl

1
Yani const &aralık tabanlı için aptalca olduğunu düşünüyorsunuz , çünkü cv- qualification ile aptalca bir şey yapan hayali bir programcının ilgisiz bir hayali örneğini yazdınız mı? ... Tamam o zaman
underscore_d
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.