Как сделать переход на C ++ 11?


35

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

Я знаю, что в стандартной библиотеке C ++ есть много контейнеров, таких как векторы, карты и строки, и C ++ 11 добавляет к этому только наличие std :: array и ranged loop.

Как лучше всего научиться использовать эти современные языковые возможности и какие из них подходят для каких моментов? Верно ли, что разработка программного обеспечения в C ++ в настоящее время в основном свободна от ручного управления памятью?

Наконец, какой компилятор я должен использовать, чтобы максимально использовать новый стандарт? Visual Studio имеет отличные средства отладки, но даже VS2012, кажется, имеет ужасную поддержку C ++ 11.


2
Я бы сказал, что называть поддержку VS2012 C ++ 11 «ужасной» немного преувеличено, но это, безусловно, могло бы быть и лучше (отсутствие списков инициализаторов особенно раздражает тестовый / игрушечный код). Но обратите внимание, что они объявили, что будут поставлять обновления компилятора независимо от остальной части VS, поэтому, я думаю, мы можем надеяться на довольно много функций C ++ 11 в VS2012 в течение 2013 года.
Martin Ba

3
Сначала я подумал, что предлагать его для изучения C ++ 11 было бы странно, но, видя, что вы все еще застряли на земле C-With-Classes ... Десять лет назад я читал Accelerated C ++ от Koenig / Moo . К тому времени я уже занимался шаблонным метапрограммированием (я только прочитал его для обзора), но это все еще было похоже на откровение. (С тех пор я использовал его как основу для преподавания C ++.) Исходя из C С классами , книга может показать вам совершенно новый язык, который вы не знали, который у вас был в вашем распоряжении. Это всего 250 страниц, и вы можете быстро перейти к чему-то специфичному для C ++ 11, но IMO - это стоящий шаг.
2012 г.,

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

  • Наконец, узнайте, как действует правило трех:

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

6
Есть ли некоторые обязательные принципы для этих правил? Это выглядит как хороший список предложений, но ... Как ваш ответ на этот вопрос через Google, как ваш ответ помогает мне принципиально подобрать C ++ 11 и использовать его, не оборачиваясь вокруг оси C ++? ?
Роберт Харви,

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

@FabioFracassi: Упс. Я написал ясно, чтобы контрастировать std::for_each, а не с диапазоном . Я удалил его, чтобы избежать путаницы.
Джон Пурди

1
Я бы обновил, если бы не было std::for_each(). Когда у вас есть лямбда, это, конечно, лучше, чем традиционный forцикл. С forциклом, основанным на диапазоне, это может быть не так, но вы не написали « forцикл на основе диапазона ».
2012 г.

@Sbi: На мой взгляд, термин « forцикл» включает в себя « forцикл на основе диапазона ». Я отредактировал с большим количеством объяснений и примером, чтобы прояснить, спасибо.
Джон Перди

12

В качестве отправной точки:

  • Прекратите использовать char*для строк. Используйте std::stringили std::wstringи просто смотрите, как ваш код становится короче, удобочитаемее и безопаснее
  • Прекратите использовать массивы в стиле C (вещи, объявленные с [ ]) и используйте std::vectorили какой-либо другой соответствующий класс контейнера. Приятно то std::vector, что он знает свою собственную длину, он очищает свое содержимое, когда выходит из области видимости, его легко перебирать, и он становится больше, когда вы добавляете больше элементов. Но есть и другие коллекции, которые могут работать еще лучше для ваших обстоятельств.
  • Используйте std::unique_ptr- и учитесь std::moveпочти сразу. Так как это может привести к некоторым noncopyable объектов, лени иногда может послать вас к std::shared_ptr- и вы можете иметь некоторые подлинные случаи использования для std::shared_ptrа
  • Используйте autoпри объявлении итераторов и типов, которые зависят от более ранних объявлений (например, раньше вы объявляли вектор чего-либо, теперь вы объявляете что-то, используйте auto)
  • for_eachВсегда используйте алгоритмы и необработанное «для», так как это избавляет других от тщательного чтения вашего цикла, чтобы сделать вывод, что вы фактически выполняете итерацию по всей коллекции и т. Д. Если ваш компилятор поддерживает «диапазон для», то используйте его снова for_each. Learn тривиальных вызовов алгоритма , как iota, generate, accumulate, find_ifи так далее.
  • Используйте лямбды - это простой способ использовать алгоритмы. Они также открывают двери для гораздо большего.

Не слишком задумывайтесь о том, какой компилятор использовать. «Ужасный, ужасный» недостаток поддержки C ++ 11 в VS2012 состоит в том, что нет шаблонов с переменными параметрами (да, вы только что собирались использовать шаблоны с переменными параметрами), а {}инициализатор отсутствует. Я тоже этого хочу, но вряд ли перестану использовать полезный инструмент разработки.

Второе, что нужно сделать после принятия std::- начать думать о RAII. В любое время у вас есть

  • стартовое действие
  • серия действий с чем-то, что вы получили от начала действия
  • действие по очистке, которое должно произойти даже в случае исключений

Тогда у вас есть конструктор, несколько функций-членов и деструктор. Напишите класс, который позаботится об этом для вас. Возможно, вам даже не придется писать ctor и dtor. Помещение shared_ptrпеременной-члена в класс является примером RAII - вы не пишете код управления памятью, но когда ваш экземпляр выходит из области видимости, происходят правильные вещи. Разверните, что на ваших глазах такие вещи, как закрытие файлов, освобождение дескрипторов, блокировок и т. Д., Станут проще и меньше (при этом устраняются утечки).

Если вы чувствуете себя по-настоящему уверенно, сделайте чистку printfв пользу cout, избавьтесь от макросов ( #defineвещей) и начните изучать некоторые «продвинутые идиомы», такие как PIMPL. У меня есть целый курс по этому вопросу в Pluralsight, который вы, вероятно, можете посмотреть, используя их бесплатную пробную версию.


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

Не могу дождаться списков инициализаторов ... жду, чтобы узнать, когда мы их получим ...
Кейт Грегори

Другим важным недостатком в VS2012 являются «ссылки на значения v3», то есть автоматически сгенерированный конструктор перемещения и назначение перемещения.
Mr.C64

3

Как лучше всего научиться использовать эти современные языковые возможности и какие из них подходят для каких моментов?

По программированию. Опыт - лучший способ учиться.

В C ++ 11 появилось много новых функций (auto, rvalue, новые умные указатели - это только некоторые из них). Лучше всего начать с их использования и читать о них, когда вы можете, и когда вы найдете интересную статью.

Верно ли, что разработка программного обеспечения в 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.
Рок Марти
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.