По-перше, кілька правил:
Використовуйте std::unique_ptr
як не накладний розумний вказівник. Вам не потрібно буде часто турбуватися із сирими вказівниками. std::shared_ptr
в більшості випадків також непотрібно. Бажання спільної власності найчастіше зраджує відсутність думки про право власності.
Використовувати std::array
для масивів статичної довжини та std::vector
для динамічних.
Широко використовуйте загальні алгоритми, зокрема:
<algorithm>
<numeric>
<iterator>
<functional>
Використовуйте auto
та, decltype()
де вони приносять користь читабельності. Зокрема, коли ви хочете оголосити якусь річ, але такого типу, який вам не цікавий, наприклад, ітератор або складний тип шаблону, використовуйте auto
. Коли ви хочете оголосити річ з точки зору типу іншої речі, використовуйте decltype()
.
Зробіть речі безпечними для друку, коли зможете. Якщо у вас є твердження, що примушують інваріантів до певного виду речі, цю логіку можна централізувати за типом. І це не обов'язково спричиняє будь-які надмірні витрати. Не слід також говорити про те, що (T)x
слід уникати ролі в стилі C ( ) на користь більш чітких (і пошукових!) C ++ - стилів (наприклад, static_cast
).
Нарешті, знайте, як правило три:
- Деструктор
- Конструктор копіювання
- Оператор призначення
Стало правилом п'яти з додаванням конструктора переміщення та оператора призначення переміщення. І зрозуміти взагалі посилання на оцінку і як уникнути копіювання.
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);