Сначала несколько практических правил:
Используйте std::unique_ptr
в качестве интеллектуального указателя без накладных расходов. Вы не должны беспокоиться о сырых указателях все это часто. std::shared_ptr
также не требуется в большинстве случаев. Желание совместного владения часто выдает в первую очередь отсутствие мысли о владении.
Используйте std::array
для массивов статической длины и std::vector
для динамических.
Широко используйте универсальные алгоритмы, в частности:
<algorithm>
<numeric>
<iterator>
<functional>
Используйте auto
и decltype()
везде, где они улучшают читабельность. В частности, когда вы хотите объявить вещь, но типа, который вас не волнует, например, итератор или сложный тип шаблона, используйте auto
. Если вы хотите объявить вещь с точки зрения типа другой вещи, используйте decltype()
.
Делайте вещи безопасными, когда можете. Когда у вас есть утверждения, которые обеспечивают инварианты для определенного вида вещей, эта логика может быть централизована в типе. И это не обязательно приводит к накладным расходам во время выполнения. Само собой разумеется, что (T)x
следует избегать приведений в стиле C ( ) в пользу более явных (и доступных для поиска!) Приведений в стиле C ++ (например, static_cast
).
Наконец, узнайте, как действует правило трех:
- Destructor
- Копировать конструктор
- Оператор присваивания
Стало правилом пяти с добавлением конструктора перемещения и оператора присваивания перемещения. И понять rvalue ссылки в целом и как избежать копирования.
C ++ - сложный язык, поэтому сложно определить, как лучше всего его использовать. Но практика хорошей разработки на C ++ принципиально не изменилась с C ++ 11. Вы по-прежнему должны отдавать предпочтение контейнерам, управляемым памятью, а не ручному управлению памятью - умные указатели позволяют легко и эффективно делать это.
Я бы сказал, что современный C ++ действительно в основном свободен от ручного управления памятью - преимущество модели памяти C ++ в том, что она детерминированная , а не ручная. Предсказуемые освобождения обеспечивают более предсказуемую производительность.
Что касается компилятора, G ++ и Clang являются конкурентоспособными с точки зрения возможностей C ++ 11 и быстро догоняют их недостатки. Я не использую Visual Studio, поэтому не могу говорить ни за, ни против.
Напоследок заметка о std::for_each
: избегайте этого вообще.
transform
, accumulate
И erase
- remove_if
это старый добрый функционал map
, fold
и filter
. Но for_each
он более общий и, следовательно, менее значимый - он не выражает никаких намерений, кроме зацикливания. Кроме того, он используется в тех же ситуациях, что и диапазон for
, и синтаксически тяжелее, даже когда используется без точек. Рассмотреть возможность:
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);