Як зробити перехід на C ++ 11?


35

Я певний час програмував на C ++, але в основному речі зосереджені на особливостях C ++ низького рівня. Під цим я маю на увазі в основному роботу з покажчиками та необробленими масивами. Я думаю, що така поведінка відома як використання C ++ як C з класами. Незважаючи на це, я нещодавно спробував С лише нещодавно вперше. Я був приємно здивований тим, як такі мови, як C # та Java, приховують ці деталі у зручних стандартних бібліотечних класах, таких як Словники та Списки.

Я знаю, що стандартна бібліотека C ++ має багато контейнерів, таких як вектори, карти та рядки, а C ++ 11 лише додає до цього, маючи std :: масив та діапазони циклів.

Як мені найкраще навчитися використовувати ці особливості сучасної мови та які підходять для яких моментів? Чи правильно, що інженерія програмного забезпечення на C ++ сьогодні переважно не має ручного управління пам'яттю?

Нарешті, який компілятор я повинен використовувати, щоб максимально використати новий стандарт? Visual Studio має чудові інструменти для налагодження, але навіть VS2012, здається, має жахливу підтримку C ++ 11.


2
Я б сказав, що виклик підтримки VS2012 C ++ 11 "жахливий" трохи перебільшений, але це, звичайно, може бути краще (відсутні списки ініціалізаторів особливо дратують код тесту / іграшки). Але зауважте, що вони оголосили, що надсилатимуть оновлення компілятора незалежно від решти VS, тому, мабуть, ми можемо сподіватися на досить багато функцій C ++ 11 у VS2012 протягом 2013 року.
Martin Ba

3
Спочатку я думав, що запропонувати це вивчити C ++ 11 було б дивно, але побачивши, що ви все ще застрягли в землі C-With-Classes ... Десятиліття тому назад я прочитав прискорений C ++ від Koenig / Moo . На той момент я вже робив метапрограмування шаблонів (я читав його лише для огляду), але це все одно відчувало як одкровення. (З тих пір я використовував це як основу для навчання C ++.) Починаючи з C Classes , книга може показати вам зовсім нову мову, яку ви не знали, що маєте в своєму розпорядженні. Це всього 250 сторінок, і ви можете швидко перейти до чогось, що стосується C ++ 11, але IMO - це вагомий крок.
sbi

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

Відповіді:


50

По-перше, кілька правил:

  • Використовуйте 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);

6
Чи є якісь принципи обов'язкових для цих правил? Це здається приємним списком пропозицій, але ... Як сторонній чоловік, який приходить на це запитання через Google, як ваша відповідь допомагає мені підібрати C ++ 11 принципово і використовувати його, не обертаючись навколо вісі C ++ ?
Роберт Харві

3
+1 для списку, але у мене є невелика нитка: коли (справедливо) попереджую проти, std::for_eachя очікував би, що діапазон, заснований на циклі, буде кращою заміною, ніж звичайний for.
Фабіо Фракассі

@FabioFracassi: На жаль. Я писав просто, щоб контрастувати з std::for_each, а не з діапазоном . Я її видалив, щоб уникнути плутанини.
Джон Перді

1
Я б оновив, якби не std::for_each(). Коли у вас лямбда, це, звичайно, краще, ніж традиційна forпетля. З forциклом на основі діапазону, що може бути не так, але ви не написали " forцикл на основі діапазону ".
sbi

@sbi: На мій погляд, термін " forцикл" включає " forцикл на основі діапазону ". Я відредагував більше пояснень та приклад для уточнення, дякую.
Джон Перді

12

Як вихідний пункт:

  • Перестаньте використовувати char*для струн. Використовуйте std::stringабо std::wstringпросто спостерігайте за тим, як ваш код стає коротшим, читабешим і безпечнішим
  • Перестаньте використовувати масиви у стилі С (речі, декларовані разом із [ ]) та використовуйте std::vectorчи інший відповідний клас контейнерів Приємно в тому std::vector, що він знає власну довжину, він очищає його вміст, коли він виходить за межі, його легко перебрати, і він зробить себе більшим, коли ви додасте більше елементів. Але є й інші колекції, які можуть працювати ще краще для ваших обставин.
  • Використовуйте std::unique_ptr- і вчіться std::moveмайже одразу. Так як це може привести до деяких noncopyable об'єктів, ліні іноді може послати вас до std::shared_ptr- і ви можете мати деякі справжні випадки використання для std::shared_ptrа
  • Використовуйте autoпри оголошенні ітераторів та типів, які залежать від попередніх декларацій (наприклад, раніше ви декларували вектор чогось, тепер декларуєте щось, використовуйте auto)
  • Використовуйте алгоритми та for_eachбільше "raw for", коли зможете, оскільки це позбавляє інших від уважного читання вашого циклу, щоб зробити висновок про те, що ви насправді повторюєте всю колекцію тощо. Якщо ваш компілятор підтримує "range for", тоді використовуйте його for_each. Learn тривіальних викликів алгоритму , як iota, generate, accumulate, find_ifі так далі.
  • Використовуйте лямбда - це найпростіший спосіб використання алгоритмів. Вони також відкривають двері для набагато більше.

Не надто працюйте над тим, який компілятор використовувати. "Страшна, жахлива" відсутність підтримки C ++ 11 у VS2012 полягає в тому, що шаблонів не є варіативними (так, ви просто збиралися використовувати різноманітні шаблони) і {}ініціалізатора немає. Я теж хочу цього, але навряд чи я перестану користуватися корисним інструментом розробки.

Друге, що потрібно зробити, обнявшись std::, - почати думати про RAII. У будь-який час

  • стартову дію
  • серія дій з чимось, що ви отримали від початку дії
  • дії з очищення, які мають відбутися навіть у випадку винятків

Тоді у вас є конструктор, ряд функцій членів та деструктор. Напишіть клас, який піклується про це за вас. Можливо, вам навіть не доведеться писати ctor та dtor. Поставлення shared_ptrзмінної як члена класу є прикладом RAII - ви не пишете код управління пам’яттю, але коли ваш екземпляр вийде за межі, то відбудуться правильні речі. Розширіть це роздуми, щоб охопити такі речі, як закриття файлів, звільнення ручок, замків тощо та код, просто стане простішим та меншим (усуваючи при цьому витоки) перед вашими очима.

Якщо ви відчуваєте себе по-справжньому впевнено, чистіть printfна користь cout, позбавтеся від макросів ( #defineматеріалів) та почніть вивчати деякі "просунуті ідіоми", наприклад, PIMPL. У мене є цілий курс з цього приводу Pluralsight, який ви, напевно, можете переглянути, використовуючи їх безкоштовну пробну версію.


2
Мені подобається, як ти ставишся до нього саркастично, що скоро не використовуєш різноманітні шаблони, але я думаю, що у відсутності рівномірної ініціалізації відсутнє щось дійсно важливе для повсякденного програмування.
sbi

Не можете чекати списків ініціалізаторів ... чекаю, коли дізнаємось, коли ми їх отримаємо ...
Кейт Грегорі

Ще одним важливим недоліком у VS2012 є "рецензування посилань v3", тобто автоматичний створений конструктор переміщення та призначення переміщення.
Mr.C64

3

Як мені найкраще навчитися використовувати ці особливості сучасної мови та які підходять для яких моментів?

За програмуванням. Досвід - найкращий спосіб вчитися.

C ++ 11 має безліч нових функцій (автоматичне, оцінювання, нові смарт-покажчики - лише декілька). Найкраще почати - це просто почати користуватися ними та читати про них, коли тільки можна, і щоразу, коли ви знайдете цікаву статтю.

Чи правильно, що інженерія програмного забезпечення на C ++ сьогодні переважно не має ручного управління пам'яттю?

Це залежить від того, що вам потрібно зробити. Більшість програм можуть уникнути розумних покажчиків і забути про управління пам'яттю. Є ще додатки, які не можуть так легко вийти (наприклад, якщо їм потрібне місце розміщення чи спеціальний розподільник пам'яті з будь-якої причини).

Якщо вам потрібно використовувати Qt, вам доведеться використовувати їх правила для управління пам'яттю.

який компілятор я повинен використовувати, щоб максимально використати новий стандарт?

Що б ви не мали, що підтримує найновіший стандарт:

але жоден компілятор не підтримує всі функції.


-7

Мій університет досі використовує C ++ для викладання. Я програмував C ++ протягом 5 років, і зараз я аспірант. Звичайно, зараз я використовую багато Java, Ruby і т. Д. Я дуже рекомендую не надто поспішати з такими функціями на мові, як Java. На мій досвід і думку, після низького рівня особливостей C ++. Ви повинні вивчити такі теми, як загальне програмування на C / C ++, як створення класу шаблонів, функцій шаблонів, перезапис операторів, віртуальних методів, розумних покажчиків. Для об’єктно-орієнтованої частини дизайну є багато функцій, які мають C ++, а Java не любить багатонаступництво. Спадкування є потужним, але й небезпечним. Рівень реалізації об'єктно-орієнтованого дизайну в C ++ також є хорошою темою. Міжпроцесовий зв'язок, потокові передачі також важливі для C ++.

Для компілятора та налагоджувача. Я знаю, що візуальна студія є приголомшливою. Але я дуже рекомендую вам вивчити GDB, Valgrind та Make still, і бути хорошим у цих інструментах. Microsoft надзвичайна, але вона зробила занадто багато для вас. Будучи студентом, вам справді потрібно вивчити ті речі, які Microsoft зробив і ви. Для компілятора G ++ хороший від GNU.

Зрештою, після стількох років, як я справді відчуваю, найважливішими речами є функції низького рівня, такі як необроблений масив. Вектор - це просто динамічний масив. Це мої рекомендації, щось, можливо, занадто суб'єктивне, просто прийміть те, що ви вважаєте правильним.


6
Як це відповідає на питання? Питання не в загальному вивченні C ++, а в переході на C ++ 11.
Roc Martí
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.