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);