Jak przejść na C ++ 11?


35

Od jakiegoś czasu programuję w C ++, ale przede wszystkim koncentruję się wokół niskopoziomowych funkcji C ++. Rozumiem przez to głównie pracę ze wskaźnikami i surowymi tablicami. Myślę, że takie zachowanie jest znane jako używanie C ++ jako C z klasami. Mimo to wypróbowałem C dopiero niedawno. Byłem mile zaskoczony, jak języki takie jak C # i Java ukrywają te szczegóły w wygodnych standardowych klasach bibliotek, takich jak Słowniki i Listy.

Wiem, że standardowa biblioteka C ++ ma również wiele kontenerów, takich jak wektory, mapy i łańcuchy, a C ++ 11 dodaje do tego tylko to, że posiada std :: array i pętle dystansowe.

Jak najlepiej nauczyć się korzystać z tych nowoczesnych funkcji językowych i które są odpowiednie dla jakich chwil? Czy to prawda, że ​​inżynieria oprogramowania w C ++ jest obecnie w większości wolna od ręcznego zarządzania pamięcią?

Na koniec, którego kompilatora powinienem użyć, aby w pełni wykorzystać nowy standard? Visual Studio ma doskonałe narzędzia do debugowania, ale nawet VS2012 wydaje się mieć straszną obsługę C ++ 11.


2
Powiedziałbym, że nazwanie obsługi C ++ 11 VS2012 „straszną” jest nieco przesadzone, ale z pewnością mogłoby być lepsze (brak list inicjalizacyjnych jest szczególnie denerwujący dla kodu testowego / zabawkowego). Ale zauważ, że ogłosili, że będą dostarczać aktualizacje kompilatora niezależnie od reszty VS, więc sądzę, że możemy mieć nadzieję na całkiem sporo funkcji C ++ 11 w VS2012 w 2013 roku.
Martin Ba,

3
Na początku myślałem, że zasugerowanie tego do nauki C ++ 11 byłoby dziwne, ale widząc, że wciąż utkniesz w krainie C-With-Classes ... Dziesięć lat temu czytałem Accelerated C ++ Koeniga / Moo . Do tego czasu faktycznie zajmowałem się metaprogramowaniem szablonów (czytałem go tylko do recenzji), ale nadal czułem się jak rewelacja. (Od tego czasu używałem go jako podstawy do nauczania C ++.) Pochodząca z C Dzięki Classes książka może pokazać ci zupełnie nowy język, o którym nie wiedziałeś, że masz do dyspozycji. To tylko 250 stron, a następnie możesz szybko przejść do czegoś specyficznego dla C ++ 11, ale IMO jest wartym kroku.
sbi

4
g++ -std=c++11
fredoverflow

Odpowiedzi:


50

Po pierwsze, kilka praktycznych zasad:

  • Użyj std::unique_ptrjako inteligentny wskaźnik bez narzutów. Nie powinieneś zbyt często zawracać sobie głowy surowymi wskaźnikami. std::shared_ptrjest również niepotrzebne w większości przypadków. Chęć współwłasności często zdradza przede wszystkim brak myślenia o własności.

  • Użyj std::arraydo tablic o długości statycznej i std::vectordo dynamiki.

  • Szeroko stosuj ogólne algorytmy, w szczególności:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • Zastosowanie autoi decltype()wszędzie tam, gdzie zwiększają czytelność. W szczególności, jeśli chcesz zadeklarować rzecz, ale takiego typu, na którym ci nie zależy, na przykład iteratora lub złożonego typu szablonu, użyj auto. Jeśli chcesz zadeklarować rzecz pod względem rodzaju innej rzeczy, użyj decltype().

  • Uczyń wszystko bezpiecznym, gdy możesz. Kiedy masz twierdzenia, które wymuszają niezmienniki na konkretny rodzaj rzeczy, logika ta może być scentralizowana w jednym typie. A to niekoniecznie oznacza narzut związany z czasem działania. Powinno być również (T)xoczywiste , że należy unikać rzutów w stylu C ( ) na rzecz bardziej wyraźnych (i możliwych do przeszukiwania!) Rzutów w stylu C ++ (np static_cast.).

  • Wreszcie, dowiedz się, jak zasada trzech:

    • Burzyciel
    • Skopiuj konstruktor
    • Operator przypisania

    Stała się regułą piątki dzięki dodaniu konstruktora ruchu i operatora przypisania ruchu. I rozumiem ogólnie odniesienia do wartości i jak uniknąć kopiowania.

C ++ jest złożonym językiem, więc jest to trudne do scharakteryzowania, jak najlepiej wykorzystać wszystkie z nich. Ale praktyki dobrego programowania w C ++ nie zmieniły się zasadniczo w C ++ 11. Nadal powinieneś preferować kontenery zarządzane pamięcią niż ręczne zarządzanie pamięcią - inteligentne wskaźniki ułatwiają to skutecznie.

Powiedziałbym, że współczesny C ++ jest w zasadzie wolny od ręcznego zarządzania pamięcią - zaletą modelu pamięci C ++ jest to, że jest deterministyczny , a nie ręczny. Przewidywalne zwolnienia przyczyniają się do bardziej przewidywalnej wydajności.

Jeśli chodzi o kompilator, zarówno G ++, jak i Clang są konkurencyjne pod względem funkcji C ++ 11 i szybko nadrabiają swoje niedociągnięcia. Nie używam Visual Studio, więc nie mogę mówić ani za, ani przeciw.

Na koniec uwaga na temat std::for_each: unikaj tego w ogóle.

transform, accumulateI erase- remove_ifsą stare, dobre funkcjonalne map, foldi filter. Ale for_eachjest bardziej ogólny, a zatem mniej znaczący - nie wyraża żadnych zamiarów poza zapętlaniem. Poza tym jest używany w tych samych sytuacjach, co oparte na zakresie fori jest syntaktycznie cięższy, nawet jeśli jest używany bez punktów. Rozważać:

for (const auto i : container)
    std::cout << i << '\n';

std::for_each(container.begin(), container.end(), [](int i) {
    std::cout << i << '\n';
});

for (const auto i : container)
    frobnicate(i);

std::for_each(container.begin(), container.end(), frobnicate);

6
Czy istnieją jakieś wiążące zasady dotyczące tych zasad? Wygląda na ładną listę sugestii, ale ... Jako outsider przybywający do tego pytania za pośrednictwem Google, w jaki sposób twoja odpowiedź pomaga mi podnieść C ++ 11 w sposób zgodny z zasadami i używać go bez owijania się wokół osi C ++ ?
Robert Harvey

3
+1 za listę, ale mam mały nitpick: kiedy (słusznie) ostrzeżenie przeciwko std::for_eachoczekiwałbym, że zakres oparty na pętli będzie lepszym zamiennikiem niż zwykły for.
Fabio Fracassi

@FabioFracassi: Ups. Napisałem zwykły kontrast std::for_each, nie oparty na zakresie . Usunąłem go, aby uniknąć zamieszania.
Jon Purdy

1
Zaktualizowałbym, gdyby nie to std::for_each(). Kiedy masz lambda, jest to z pewnością lepsze niż tradycyjna forpętla. Z forpętlą opartą na zakresie, która może nie być przypadkiem, ale nie napisałeś „ forpętli opartej na zakresie ”.
sbi

@sbi: Moim zdaniem termin „ forpętla” obejmuje „ forpętlę opartą na zakresie ”. Zredagowałem z dodatkowym wyjaśnieniem i przykładem do wyjaśnienia, dziękuję.
Jon Purdy

12

Jako punkt wyjścia:

  • Przestań używać char*ciągów znaków. Użyj std::stringlub std::wstringpo prostu obserwuj, jak Twój kod staje się krótszy, bardziej czytelny i bezpieczniejszy
  • Przestań używać tablic w stylu C (rzeczy zadeklarowane za pomocą [ ]) i użyj std::vectorinnej odpowiedniej klasy kontenera. Zaletą std::vectorjest to, że zna swoją długość, czyści zawartość, gdy wychodzi poza zakres, łatwo ją powtarzać i powiększa się, gdy dodajesz więcej przedmiotów. Ale istnieją inne kolekcje, które mogą działać jeszcze lepiej w danych okolicznościach.
  • Użyj std::unique_ptr- i ucz się std::moveniemal natychmiast. Ponieważ może to prowadzić do pewnych noncopyable obiektów, lenistwo może czasami wysłać kierunku std::shared_ptr- a może masz jakieś autentyczne przypadki użycia dla std::shared_ptrjak dobrze
  • Użyj, autogdy deklarujesz iteratory i typy, które zależą od wcześniejszych deklaracji (np. Wcześniej zadeklarowałeś wektor czegoś, teraz coś deklarujesz, użyj auto)
  • Używaj algorytmów i for_each„surowego” dla, gdy tylko możesz, ponieważ oszczędza to innym od uważnego czytania pętli, aby dojść do wniosku, że w rzeczywistości iterujesz całą kolekcję itp. Jeśli twój kompilator obsługuje „zakres dla”, użyj go for_each. Dowiedz się trywialne połączeń algorytm jak iota, generate, accumulate, find_ifi tak dalej.
  • Użyj lambdas - są łatwym sposobem na wykorzystanie algorytmów. Otwierają także drzwi do znacznie więcej.

Nie przejmuj się zbytnio tym, jakiego kompilatora użyć. W „straszne, straszne” brak C ++ 11 wsparcie w VS2012 jest że nie ma o zmiennej liczbie argumentów szablony (yeah prawy, byłeś tylko o użycie zmiennej liczbie argumentów szablonów) oraz {}inicjator nie ma. Ja też tego chcę, ale raczej nie przestanę nad tym używać przydatnego narzędzia programistycznego.

Drugą rzeczą do zrobienia, po objęciu std::, jest rozpoczęcie myślenia o RAII. Kiedykolwiek masz

  • rozpoczęcie działania
  • seria akcji z czymś, co otrzymałeś od rozpoczęcia akcji
  • akcja czyszczenia, która musi się zdarzyć nawet w przypadku wyjątków

Zatem masz konstruktor, szereg funkcji składowych i destruktor. Napisz zajęcia, które się tym zajmą. Być może nawet nie będziesz musiał napisać ctor i dtor. Umieszczenie shared_ptrzmiennej klasy jako członka jest przykładem RAII - nie piszesz kodu zarządzania pamięcią, ale gdy twoja instancja wykracza poza zakres, właściwe rzeczy się zdarzają. Rozwiń to myślenie, aby objąć takie rzeczy jak zamykanie plików, zwalnianie uchwytów, blokad itp., A kod stanie się po prostu prostszy i mniejszy (eliminując przecieki) na twoich oczach.

Jeśli czujesz się naprawdę pewny siebie, oczyść się printfna korzyść cout, pozbądź się makr ( #definerzeczy) i zacznij uczyć się „zaawansowanych idiomów”, takich jak PIMPL. Mam cały kurs na ten temat w Pluralsight, który prawdopodobnie można obejrzeć, korzystając z bezpłatnego okresu próbnego.


2
Podoba mi się to, że jesteś sarkastyczny w stosunku do niego, że nie używa szablonów variadic w najbliższym czasie, ale myślę, że brak jednolitej inicjalizacji to coś naprawdę ważnego w codziennym programowaniu.
sbi

Nie mogę się doczekać list inicjalizacyjnych ... czekam, aby dowiedzieć się, kiedy je otrzymamy ...
Kate Gregory

Innym ważnym brakiem w VS2012 są „referencje wartości v3”, tj. Automatycznie generowany konstruktor ruchu i przypisanie ruchu.
Mr.C64

3

Jak najlepiej nauczyć się korzystać z tych nowoczesnych funkcji językowych i które są odpowiednie dla jakich chwil?

Przez programowanie. Doświadczenie to najlepszy sposób na naukę.

C ++ 11 ma wiele nowych funkcji (auto, rvalue, nowe inteligentne wskaźniki - żeby wymienić tylko kilka). Najlepiej zacząć od ich użycia i poczytać o nich, kiedy tylko możesz i kiedy znajdziesz interesujący artykuł.

Czy to prawda, że ​​inżynieria oprogramowania w C ++ jest obecnie w większości wolna od ręcznego zarządzania pamięcią?

To zależy od tego, co musisz zrobić. Większość aplikacji potrafi uniknąć inteligentnych wskaźników i zapomnieć o zarządzaniu pamięcią. Nadal istnieją aplikacje, które nie mogą tak łatwo uciec (na przykład, jeśli wymagają nowego umieszczenia lub niestandardowego przydziału pamięci z dowolnego powodu).

Jeśli potrzebujesz użyć Qt, będziesz musiał użyć ich reguł do zarządzania pamięcią.

jakiego kompilatora powinienem użyć, aby w pełni wykorzystać nowy standard?

Cokolwiek masz pod ręką, które obsługuje najnowszy standard:

ale żaden kompilator nie obsługuje wszystkich funkcji.


-7

Mój uniwersytet nadal używa C ++ do nauczania. Programuję w C ++ od 5 lat, a teraz jestem studentem. Oczywiście, teraz używam dużo Java, Ruby itp. Naprawdę polecam, abyś nie spieszył się z tymi funkcjami w języku takim jak Java. Według mojego doświadczenia i opinii, po niskim poziomie funkcji C ++. Powinieneś przyjrzeć się tematom takim jak ogólne programowanie w C / C ++, takim jak tworzenie klasy szablonów, funkcje szablonów, zastępowanie operatora, metody wirtualne, inteligentne wskaźniki. W przypadku części zorientowanej obiektowo istnieje wiele funkcji C ++, a Java nie, takich jak dziedziczenie wielokrotne. Dziedziczenie jest potężne, ale także niebezpieczne. Poziom implementacji projektowania obiektowego w C ++ jest również dobrym tematem. Komunikacja między procesami, wątki są również ważne w C ++.

Dla kompilatora i debuggera. Wiem, że studio wizualne jest niesamowite. Ale naprawdę polecam uczyć się GDB, Valgrind i Make still i być dobrym w tych narzędziach. Microsoft jest niesamowity, ale zrobił dla ciebie zbyt wiele rzeczy. Jako student naprawdę musisz nauczyć się tych rzeczy, które Microsoft zrobił także tobie. Dla kompilatora G ++ jest dobry z GNU.

W końcu po tylu latach naprawdę czuję, że najważniejsze są funkcje niskiego poziomu, takie jak surowa tablica. Wektor jest naprawdę tylko dynamiczną tablicą. To są moje rekomendacje, coś może zbyt subiektywnego, po prostu weź to, co uważasz za słuszne.


6
Jak to odpowiada na pytanie? Pytanie nie dotyczy ogólnie nauki C ++, ale przejścia na C ++ 11.
Roc Martí
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.