Po pierwsze, kilka praktycznych zasad:
Użyj std::unique_ptr
jako inteligentny wskaźnik bez narzutów. Nie powinieneś zbyt często zawracać sobie głowy surowymi wskaźnikami. std::shared_ptr
jest 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::array
do tablic o długości statycznej i std::vector
do dynamiki.
Szeroko stosuj ogólne algorytmy, w szczególności:
<algorithm>
<numeric>
<iterator>
<functional>
Zastosowanie auto
i 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)x
oczywiste , ż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
, accumulate
I erase
- remove_if
są stare, dobre funkcjonalne map
, fold
i filter
. Ale for_each
jest 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 for
i 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);