Yeni C ++ 11 'otomatik' özelliğini, özellikle döngülerde kullanmalı mıyım?


20

autoAnahtar kelimeyi, özellikle döngüler için kullanmanın avantajları / dezavantajları nelerdir?

for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->something();
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->second->something();
}

for(auto it = x.begin(); it != x.end(); it++ )
{
   it->??
}

Eğer bir harita ya da bilemeyiz bir vektör için bir yineleyici sahip olup olmadığını bilmiyorsanız gibi görünüyor kullanımına olsun firstya secondveya nesnenin sadece doğrudan erişim özellikleri, hayır?

Bu bana anahtar kelimenin kullanılıp kullanılmayacağına dair C # tartışmasını hatırlatıyor var. Şimdiye kadar aldığım izlenim, C ++ dünyasında insanların C # dünyasından autodaha az kavga ile anahtar kelimeyi benimsemeye hazır olmaları var. Benim için ilk içgüdüm, değişkenin türünü bilmek istememdir, böylece üzerinde ne gibi işlemler yapmayı bekleyebilirim.


3
Bekleyin! Kullanıp kullanmama konusunda bir kavga oldu varmu? Onu özledim.
pdr

21
Daha da iyisi, sadece for (auto& it : x)(veya kopyalamak istiyorsanız referans olmadan) kullanabilirsiniz
Tamás Szelei

7
İçeriğini yinelemek için bir döngü yazıyorsanız xve ne xolduğunu bile bilmiyorsanız , o döngüyü ilk etapta
yazmamalısınız

@fish: döngüler için aralık tabanlı kurallar, ama ben bilgiçlik olurdu ve yapılır: 'for (T & it: x)' yerine döngüler için aralık tabanlı kullanırken, otomatik kullanarak daha az bilgilendirici olduğunu hissediyorum. Aklımda bir tür oto kötüye kullanımı var.
martiert

Var kullanımı konusundaki mücadele, özellikle geçmişe bakıldığında, biraz saçma oldu. Bkz. Yük kült programlama .
Craig

Yanıtlar:


38

Metaprogramlama ve diğer şeyler nedeniyle türler C # türlerinden çok daha kıvrımlı ve karmaşık olabileceğinden, C ++ 'daki motivasyonlar daha aşırıdır. autoyazma ve okuma daha hızlıdır ve açık bir türden daha esnek / bakımı yapılabilir. Demek istediğim, yazmaya başlamak istiyor musun

boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it

Bu tam tip bile değil. Birkaç şablon argümanını kaçırdım.


8
+1 için örnek, ama bu aynı zamanda "modern" C ++ durumu hakkında bir şeyler söyler.
zvrba

22
@zvrba: Evet- jenerik tesisler C # 'dan çok daha güçlü.
DeadMG

4
typedef bunun içindir
gbjbaanb

19
@gbjbaanb Hayır, bunun autoiçin var. Tasarım gereği. typedefyardımcı olur, ancak autodaha fazla yardımcı olur.
Konrad Rudolph

1
typedef, "
Michael

28

Örneğinizde:

for(auto it = x.begin(); it != x.end(); i++)
{
  it->??
}

xgörünür olmak için bir deklarasyon olmalıdır . Bu nedenle türü itaçık olmalıdır. Türü xaçık değilse, yöntem çok uzun veya sınıf çok büyük.


7
Ayrıca, xbir kap için çok kötü bir değişken adıdır. Bazı durumlarda büyük olasılıkla (anlamsal olarak değerli) isme bakabilir ve olası işlemleri çıkarabilirsiniz.
Maksimum

@Max: sadece xgenel bir örnek olarak kullanılır, oldukça açıklayıcı değişken isimleri kullanma eğilimindeyim.
Kullanıcı

@User Tabii ki, bunun gerçek dünya örneği olduğunu varsaymadım;)
Max

14

İtiraz ! Yüklenen soru.

Üçüncü kodun neden içeride olduğunu açıklayabilir misiniz ??, yine de birinci ve ikinci kod yok? Adalet uğruna, kodunuz aşağıdaki gibi olmalıdır :

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->???
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->second->???
}

Orada. Kullanmasanız bile aynı sorun auto.

Ve her durumda, cevap aynıdır: Bağlam önemlidir . Bir kod parçasından ayrı olarak anlamlı bir şekilde konuşamazsınız. Şablon kullanmamış olsanız bile, somut bir tür kullanmış olsanız bile, bu sorunu sadece başka bir yere taşımış olabilirdi, çünkü kodunuzun okuyucusu bahsedilen türün bildirimini bilmek zorunda kalacaktı.

autoBu durumlarda kullanımı kodunuzu okunamaz hale getirirse, bunu kod tasarımınızda bir sorun olduğunu gösteren bir uyarı işareti olarak görmelisiniz. Tabii ki, düşük düzeyli ayrıntıların önemli olduğu durumlar vardır (bit işlemleri veya eski API ile uğraşırken olduğu gibi), bu tür durumlarda açık bir tür okunabilirliğe yardımcı olabilir. Ama genel olarak - hayır.

İlgili var(açıkça söz beri), bir de var engin konsensüs C # toplumda için kullanıyor var. Kullanımına karşı olan argümanlar genellikle yanlışlar üzerine kuruludur .


1
Bence nokta, otomatik ile sonraki koymak ne bilmiyorum ... bu kod özel "bir şey" veya "veri" yöntemi olan veri nesnesi almak için açma ile ilgili bir veri türü
Michael Shaw

1
@Ptolemy Ve benim açımdan: diğer iki kodda da (genellikle) sıradaki ne olacağını bilmiyorsunuz: Tkullanıcı kadar opak auto. Yine de birinin iyi olması, diğerinin iyi olmaması gerekir mi ?! Bu mantıklı değil. OP durumunda, Trastgele bir tür için bir stand-in. Gerçek kodda, şablonların (for typename std::vector<T>::iterator…)veya bir sınıf arayüzünün kullanımı olabilir . Her iki durumda da, gerçek tür kullanıcıdan gizlenir ve yine de bu kodu rutin olarak sorunsuz bir şekilde yazarız.
Konrad Rudolph

1
Aslında, evet. Bu bir vektörse, yapmanız gereken bilirsiniz -> ve sonra veri türünüze erişebilirsiniz. Bu bir harita ise, -> ikinci-> yapmanız gerektiğini biliyorsunuz ve sonra veri türünüze erişiminiz var, eğer otomatikse, veri türünüze erişmek için ne yapmanız gerektiğini bilmiyorsunuz. "STL koleksiyonunda bulunan veri türü nedir" ile "hangi STL toplama türüne sahibiz" ile karıştırıyorsunuz. auto bu sorunu daha da kötüleştirir.
Michael Shaw

1
@Ptolemy Tüm bu argümanlar kullanırken aynı derecede doğrudur auto. Hangi işlemlerin xbağlamdan desteklediğini görmek önemsizdir . Aslında, tip verir hayır ek bilgi: her iki durumda da size desteklenen operasyonların setini anlatmak için bazı ikincil (IDE, dokümantasyon, bilgi / bellek) gerekir.
Konrad Rudolph

1
Yani @Ptolemy sadece sen bilmiyorsun son derece dolambaçlı durumdayız true begindöner ama do biliyor std::vector<>::iteratorolduğunu. Ve size bu bilgileri önemsiz bir şekilde veremeyen kötü bir programlama aracı kullanmanız gerekir. Bu çok kıvrıktır. Gerçekte, ya ikisini de ikisini de tanıyorsunuz beginve iteratorilgili bilgileri sizin için hazır hale getirebilecek bir IDE veya editör kullanmalısınız. Her modern IDE ve programlama editörü bunu yapabilir.
Konrad Rudolph

11

PRO

Senin kodun :

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

şablon bağımlı adı nedeniyle derlenmeyecektir.

Bu doğru sözdizimidir:

for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

Şimdi tür bildiriminin ne kadar uzun olduğuna bakın. Bu, autoanahtar kelimenin neden tanıtıldığını gösterir. Bu :

for( auto it = x.begin(); it != x.end(); i++)

daha özlü. Yani, bu bir profesyonel.


CON

Biraz dikkatli olmalısın. Anahtar kelime ile autobeyan ettiğiniz türü elde edersiniz.

Örneğin :

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
  ++ it;   // ops modifying copies of vector's elements
}

vs

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v )   // mind the reference
{
  ++ it;   // ok, vector's elements modified
}

Sonuç olarak: evet, yapmalısınız, ama aşırı kullanmayın. Bazı insanlar bunu çok fazla kullanma eğilimindedir ve bir sonraki örnekte olduğu gibi her yere otomatik olarak yerleştirir:

auto i = 0;

vs

int i = 0;

auto i = 0. Suçlu. Bunu yaparım. Ama bunun 0bir tür değişmez olduğunu biliyorum int. (ve bir sekizli sabit ;-))
Laurent LA RIZZA

6

Evet yapmalısın! autotürü silmez; ne x.begin()olduğunu "bilmiyorsanız" bile , derleyici türü yanlış kullanmaya çalıştığınızda bir hata bilir ve bildirir. Ayrıca, mapa ile taklit etmek olağandışı değildir vector<pair<Key,Value>>, bu nedenle kullanarak kod autoher iki sözlük temsili için de çalışır.


4

Evet, autovarsayılan kural olarak kullanmalısınız . Açıkça belirtmek yerine ham avantajları vardır:

  • Derleyicinin zaten farkında olduğu şeyleri yazmanıza neden olmaz.
  • Değişkenlerin türünü, dönüş değeri türlerindeki herhangi bir değişikliği "takip eder" yapar.
  • Bunu yaparak , örtük dönüşümlerin sessizce başlatılmasını ve yerel değişken başlatmasında dilimlemeyi önler .
  • Şablonlarda bazı açık tip hesaplamalara olan ihtiyacı ortadan kaldırır.
  • Dönüş adlarını uzun adlarla adlandırma ihtiyacını ortadan kaldırır. (derleyici tanısından kopyalayıp yapıştırdıklarınız)

Burada bir seçim var. Başka seçeneğiniz olmadığı durumlar da vardır:

  • Bir lambda türü gibi unutulabilir tipteki değişkenlerin bildirilmesine izin verir.

Tam olarak ne yaptığını bilmeniz koşuluyla auto, hiçbir dezavantajı yoktur.

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.