C ++ 11'de hangi C ++ deyimleri kullanımdan kaldırıldı?


192

Yeni standartla, yeni şeyler yapmanın yeni yolları var ve birçoğu eski yollardan daha güzel, ancak eski yol hala iyi. Yeni standardın geriye dönük uyumluluk nedenleriyle resmi olarak çok fazla itiraz etmediği de açıktır. Yani geriye kalan soru şudur:

C ++ 11 stillerinden hangi eski kodlama yöntemleri kesinlikle daha düşüktür ve bunun yerine şimdi ne yapabiliriz?

Bunu cevaplarken, "otomatik değişkenleri kullan" gibi bariz şeyleri atlayabilirsiniz.


13
Sen olamaz deprecate deyimleri.
Pubby

6
Herb Sutter'ın Going Native 2012'deki konuşması
şunları

5
Sabit değerlerin döndürülmesi artık desteklenmemektedir. Açıkçası auto_ptrreddedildi.
Kerrek SB

27
Tabii ki yapabilirsin, Pubby. C ++ şablonları icat edilmeden önce şablonlar yapmak için bir makro tekniği vardı. Sonra C ++ onları ekledi ve eski yol kötü olarak kabul edildi.
Alan Baljeu

7
Bu sorunun gerçekten Programmers.se'ye taşınması gerekiyor.
Nicol Bolas

Yanıtlar:


173
  1. Son Sınıf : C ++ 11, finalsınıf türevini önlemek için tanımlayıcı sağlar
  2. C ++ 11 lambdas, adlandırılmış işlev nesnesi (functor) sınıflarına olan ihtiyacı önemli ölçüde azaltır.
  3. Move Constructor : std::auto_ptrRvalue referansları için birinci sınıf destek nedeniyle, çalışmaların artık gerekli olmadığı sihirli yollar .
  4. Güvenli bool : Bu daha önce belirtilmişti. C ++ 11'in açık operatörleri bu çok yaygın C ++ 03 deyimini ortadan kaldırır.
  5. Sığdırmak için Küçült : Birçok C ++ 11 STL kabı shrink_to_fit(), geçici olarak değiştirilme ihtiyacını ortadan kaldıran bir üye işlevi sağlar.
  6. Geçici Temel Sınıf : Bazı eski C ++ kütüphaneleri bu oldukça karmaşık deyimi kullanır. Hareket semantiği ile artık gerekli değil.
  7. Tür Güvenli Numaralandırma Numaralandırma C ++ 11'de çok güvenlidir.
  8. Öbek tahsisini engelleme : = deleteSözdizimi, belirli bir işlevin açıkça reddedildiğini söylemenin çok daha doğrudan bir yoludur. Bu, yığın tahsisini (yani =deleteüye için operator new), kopyaları, atamayı vb. Önlemek için geçerlidir.
  9. Templated typedef : C ++ 11'deki takma ad şablonları basit templated typedef'lere olan ihtiyacı azaltır. Bununla birlikte, karmaşık tip üreteçlerinin hala meta işlevlere ihtiyacı vardır.
  10. Fibonacci gibi bazı sayısal derleme zamanı hesaplamaları genelleştirilmiş sabit ifadeler kullanılarak kolayca değiştirilebilir
  11. result_of: Sınıf şablonunun kullanımları result_ofile değiştirilmelidir decltype. Bence result_ofkullanılabilir decltypeolduğunda kullanır .
  12. Sınıf içi üye başlatıcıları , statik olmayan üyelerin varsayılan değerlerle varsayılan başlatılması için yazmayı kaydeder.
  13. Yeni C ++ 11 kodu NULLolarak yeniden tanımlanmalıdır nullptr, ancak STL'nin neden buna karşı karar verdiklerini öğrenmek için konuşmasına bakın .
  14. İfade şablonu fanatikleri, C ++ 11'de sondaki dönüş türü işlevinin söz dizimine sahip olmaktan mutluluk duyar . Artık 30 satırlık uzun dönüş türü yok!

Sanırım orada duracağım!


Ayrıntılı şeyler için teşekkürler!
Alan Baljeu

7
Harika cevap, ama result_oflisteden grev yapardım . Hantal rağmen typenamekendinden önce gerekli diye düşünüyorum typename result_of<F(Args...)::typebazen daha kolay okunur olabilir decltype(std::declval<F>()(std::declval<Args>()...)ve kabulü ile N3436 çalışma kağıdı içine onlar (bir avantaj olarak kullanılan SFINAE için her iki çalışma decltypebu result_ofteklif vermedi)
Jonathan Wakely

14 ile ilgili olarak ben hala aynı kodu iki kez yazmak için makroları kullanmak zorunda ağlıyorum - bir kez fonksiyon gövdesi için ve bir kez decltype () deyimi için ...

2
Bu konunun bu Microsoft sayfasından C ++ diline genel bir girişte "Daha fazla bilgi için" makalesi olarak bağlandığını belirtmek isterim , ancak bu konu son derece uzmanlaşmış bir konudur! Kısa bir önerebilir miyim "Bu konu C ++ acemiler için DEĞİL!" başlığın veya bu cevabın başına tavsiye dahil mi?
Aacini

Re 12: "Sınıf içi üye başlatma" - bu yeni deyim, kullanım dışı bir deyim değil, değil mi? Cümle düzenini değiştirebilir misin? Ynt 2: Nesneler yerine türlerden (özellikle şablon parametrelerinde) geçmek istediğinizde işlevler çok kullanışlıdır. Yani kullanımdan kaldırılan functorların sadece bazı kullanımları.
einpoklum

66

Bir zamanlar birinin constdeğere göre değil, değere göre dönmesi gerektiği ileri sürüldü :

const A foo();
^^^^^

Bu çoğunlukla C ++ 98 / 03'te zararsızdı ve hatta benzeyen birkaç hatayı bile yakalamış olabilir:

foo() = a;

Ancak constC ++ 11'de geri dönmek kontrendikedir çünkü hareket semantiğini engeller:

A a = foo();  // foo will copy into a instead of move into it

Sadece rahatlayın ve kodlayın:

A foo();  // return by non-const value

9
Ancak önlenebilir hatalar artık işlevler için referans niteleyicileri kullanılarak yakalanabilir. Yukarıdaki durumda olduğu gibi A& operator=(A o)&yerine tanımlamak A& operator=(A o). Bunlar aptalca hataları önler ve sınıfların daha temel türler gibi davranmasını sağlar ve hareket semantiğini engellemez.
Joe

61

En kısa sürede vazgeçebilir 0ve NULLlehine nullptryapabilirsiniz!

Jenerik olmayan kodda kullanımı 0ya NULLda böyle büyük bir anlaşma değildir. Ancak, genel koddaki boş işaretçi sabitlerini geçmeye başlar başlamaz durum hızla değişir. Bir iletiye geçtiğinizde 0, boş gösterici sabiti olarak değil, bir olarak template<class T> func(T) Tçıkarılır int. Ve bundan sonra null işaretçi sabitine geri dönüştürülemez. Bu, yalnızca evren kullanılırsa varolmayan bir sorun bataklığına dönüşür nullptr.

C ++ 11 kullanımdan kaldırmıyor 0ve NULLboş işaretçi sabitleri olarak. Ama sanki öyle kodlamalısınız.


decltype (nullptr) nedir?

4
@GrapschKnutsch: Öyle std::nullptr_t.
Howard Hinnant

Bunu, benimsenecek yeni sözleşmeden ziyade deyim onaylanmadığı için yeniden ifade edilmesini önerin (örn. " Boş göstericilerin kullanımı 0veya NULLboş göstergeler").
einpoklum


24

C ++ 11'de temel algoritmalar yazmaktan kaçınmanızı sağlayan şeylerden biri, standart kütüphanenin sağladığı algoritmalarla birlikte lambdaların kullanılabilirliğidir.

Ben şimdi bunları kullanıyorum ve lanet döngüler tekrar yazmak yerine sadece count_if (), for_each () veya diğer algoritmalar kullanarak ne yapmak istediğinizi söylemek ne kadar inanılmaz.

Tam bir C ++ 11 standart kütüphanesi ile bir C ++ 11 derleyicisini kullandıktan sonra, standart algoritmaları kullanmak için artık iyi bir bahaneniz yok . Lambda onu öldür.

Neden?

Pratikte (algoritmaları kendim bu şekilde kullandıktan sonra), basit sözcüklerle inşa edilen bir şeyi okumak, anlamı bilmek için şifrelenmemeniz gereken bazı döngülerden çok daha kolay geliyor. Bununla birlikte, lambda argümanlarının otomatik olarak çıkarılması, sözdizimini ham döngü ile daha kolay karşılaştırılabilir hale getirmeye çok yardımcı olacaktır.

Temel olarak, standart algoritmalarla yapılan okuma algoritmaları, döngülerin uygulama ayrıntılarını gizleyen kelimeler kadar çok daha kolaydır.

Sadece daha yüksek seviyeli algoritmalar üzerinde düşünmek zorunda olduğumuzu tahmin ediyorum.


8
Aslında iyi bir mazeret var. Çok daha güzel olan Boost.Range algoritmalarını kullanıyorsunuz ;)
Nicol Bolas

10
Ben for_eachlambda ile döngü için lambda içeriği ile, döngü için eşdeğer aralık tabanlı daha iyi olduğunu görmüyorum . Kod aşağı yukarı aynı görünüyor, ancak lambda fazladan noktalama işaretleri içeriyor. boost::irangeAçıkça yineleyicileri kullananlardan daha fazla döngüye uygulamak gibi şeylerin eşdeğerlerini kullanabilirsiniz. Ayrıca döngü için menzil tabanlı daha fazla esnekliğe sahiptir, bu nedenle gerektiğinde ( returnya da tarafından break) erken çıkabilirsiniz , oysa for_eachatmanız gerekir.
Steve Jessop

5
@SteveJessop: Öyle olsa bile, aralık tabanlı forkullanılabilirlik normal it = c.begin(), const end = c.end(); it != end; ++itdeyimi geçersiz kılar .
Ben Voigt

7
@SteveJessop for_eachAlgoritmanın döngü tabanlı aralık üzerinde bir avantajı , yapamayacağınız break veya yapamayacağınızdırreturn . Yani, for_eachvücuda bakmadan derhal bildiğinizi gördüğünüzde böyle bir hile yoktur.
bames53

5
@Klaim: spesifik olmak gerekirse, örneğin std::for_each(v.begin(), v.end(), [](int &i) { ++i; });ile karşılaştırıyorum for (auto &i : v) { ++i; }. Esnekliğin çift kenarlı olduğunu kabul ediyorum ( gotoçok esnek, sorun bu). Ben sanmıyorum kullanmak mümkün olmayan kısıt breakiçinde for_eachbunu gerektiriyor ekstra ayrıntı için sürüm dengeler - kullanıcıları for_eachburada IMO o teorik kavramın bir tür fiili okunabilirliği ve rahatlık feda eden for_eachbir prensip içinde daha net ve kavramsal daha basit. Pratikte daha net veya daha basit değildir.
Steve Jessop

10

Özel sürümleri swapdaha az sıklıkta uygulamanız gerekir . C ++ 03'te, swapmaliyetli ve atma kopyalarından kaçınmak için genellikle verimli bir atma gerekli değildir ve std::swapiki kopya kullandığından, swapgenellikle özelleştirilmelidir. C ++ 'da, std::swapkullanımlar kullanılır moveve böylece odak, verimli ve fırlatmayan hareket kurucuları ve hareket atama işleçlerini uygulamaya kaydırılır. Bunlar için varsayılan genellikle iyi olduğundan, bu C ++ 03'ten çok daha az iş olacaktır.

Genellikle hangi deyimlerin kullanılacağını tahmin etmek zordur çünkü deneyim yoluyla yaratılırlar. Belki gelecek yıl bir "Etkili C ++ 11" ve bir "C ++ 11 Kodlama Standartları" nı bekleyebiliriz, çünkü gerekli deneyim henüz orada değildir.


1
Bundan şüpheliyim. Önerilen stil, taşıma ve kopya oluşturma için swap kullanmaktır, ancak std :: swap kullanmayın, çünkü bu dairesel olacaktır.
Alan Baljeu

Evet, ancak hareket oluşturucu genellikle özel bir takas çağırır veya esasen eşdeğerdir.
Ters

2

Bunun adını bilmiyorum, ancak C ++ 03 kodu genellikle eksik hareket atama yerine aşağıdaki yapı kullanılır:

std::map<Big, Bigger> createBigMap(); // returns by value

void example ()
{
  std::map<Big, Bigger> map;

  // ... some code using map

  createBigMap().swap(map);  // cheap swap
}

Bu, swapyukarıdakilerle birleştirilmiş kopya seçimi nedeniyle herhangi bir kopyalamayı önledi .


1
Örneğinizde takas gereksizdir, kopya elizyonu mapyine de dönüş değerini oluşturur . Gösterdiğiniz teknik map, sadece inşa edilmek yerine zaten mevcutsa yararlıdır . Örnek, "ucuz varsayılan kurucu" yorumu olmadan ve bu inşaat ile takas arasındaki "// ..." ile daha iyi olurdu
Jonathan Wakely

Tavsiyenize göre değiştirdim. Teşekkürler.
Andrzej

"Büyük" ve "Büyük" kullanımı kafa karıştırıcıdır. Anahtarın ve değer türünün boyutlarının neden önemli olduğunu açıklamıyorsunuz?
einpoklum

1

C ++ 11 standardını kullanan bir derleyicinin artık aşağıdaki kodda hata olmadığını fark ettiğimde:

std::vector<std::vector<int>> a;

sözde operatör içerdiği için >> dans etmeye başladım. Önceki sürümlerde bir

std::vector<std::vector<int> > a;

Daha da kötüsü, bunu hata ayıklamak zorunda kaldıysanız, bundan çıkan hata mesajlarının ne kadar korkunç olduğunu biliyorsunuz.

Ancak bunun sizin için "açık" olup olmadığını bilmiyorum.


1
Bu özellik önceki C ++ 'da zaten eklenmişti. Ya da en azından Visual C ++ yıllar önce standart tartışma başına uyguladı.
Alan Baljeu

1
@AlanBaljeu Tabii ki, derleyici / kütüphanelere standart olmayan birçok şey ekleniyor. C ++ 11'den önce "otomatik" değişken bildirimi olan tonlarca derleyici vardı, ancak daha sonra kodunuzun gerçekten başka bir şey tarafından derlenebileceğinden emin olamazdınız. Soru standart hakkındaydı, "bunu yapabilen herhangi bir derleyici var mıydı" değil.
v010dya

1

Değere göre geri dönüş artık sorun değil. Hareket semantiği ve / veya dönüş değeri optimizasyonu (derleyiciye bağlı) ile kodlama fonksiyonları, ek yük veya maliyet olmadan (çoğu zaman) daha doğaldır.


... ama hangi deyim reddedildi?
einpoklum

Bir deyim değil ama artık gerekli olmayan iyi bir uygulamadır. İsteğe bağlı derleyici destekli RVO ile bile. tr.wikipedia.org/wiki/Return_value_optimization "C ++ evriminin ilk aşamalarında, dilin bir sınıftan bir nesneyi bir işlevden etkin bir şekilde döndürememesi bir zayıflık olarak kabul edildi ....." struct Data {char bytes [ 16]; }; void f (Veri * p) {// doğrudan * p} içinde sonuç üretir int main () {Veri d; f (ve d); }
Martin A

Cevabınızı "değere göre geri dönüşten kaçınma geleneği artık vb. İle alakalı değil" şeklinde ifade etmeniz gerektiğini ima ediyordum.
einpoklum
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.