Я некоторое время программировал на C ++, но в основном это было связано с низкоуровневыми возможностями C ++. Под этим я подразумеваю в основном работу с указателями и необработанными массивами. Я думаю, что это поведение известно как использование C ++ как C с классами. Несмотря на это, я только недавно попробовал C в первый раз. Я был приятно удивлен, как языки, такие как C # и Java, скрывают эти детали в удобных классах стандартной библиотеки, таких как словари и списки.
Я знаю, что в стандартной библиотеке C ++ есть много контейнеров, таких как векторы, карты и строки, и C ++ 11 добавляет к этому только наличие std :: array и ranged loop.
Как лучше всего научиться использовать эти современные языковые возможности и какие из них подходят для каких моментов? Верно ли, что разработка программного обеспечения в C ++ в настоящее время в основном свободна от ручного управления памятью?
Наконец, какой компилятор я должен использовать, чтобы максимально использовать новый стандарт? Visual Studio имеет отличные средства отладки, но даже VS2012, кажется, имеет ужасную поддержку C ++ 11.
g++ -std=c++11
Ответы:
Сначала несколько практических правил:
Используйте
std::unique_ptr
в качестве интеллектуального указателя без накладных расходов. Вы не должны беспокоиться о сырых указателях все это часто.std::shared_ptr
также не требуется в большинстве случаев. Желание совместного владения часто выдает в первую очередь отсутствие мысли о владении.Используйте
std::array
для массивов статической длины иstd::vector
для динамических.Широко используйте универсальные алгоритмы, в частности:
<algorithm>
<numeric>
<iterator>
<functional>
Используйте
auto
иdecltype()
везде, где они улучшают читабельность. В частности, когда вы хотите объявить вещь, но типа, который вас не волнует, например, итератор или сложный тип шаблона, используйтеauto
. Если вы хотите объявить вещь с точки зрения типа другой вещи, используйтеdecltype()
.Делайте вещи безопасными, когда можете. Когда у вас есть утверждения, которые обеспечивают инварианты для определенного вида вещей, эта логика может быть централизована в типе. И это не обязательно приводит к накладным расходам во время выполнения. Само собой разумеется, что
(T)x
следует избегать приведений в стиле C ( ) в пользу более явных (и доступных для поиска!) Приведений в стиле C ++ (например,static_cast
).Наконец, узнайте, как действует правило трех:
Стало правилом пяти с добавлением конструктора перемещения и оператора присваивания перемещения. И понять 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
, и синтаксически тяжелее, даже когда используется без точек. Рассмотреть возможность:источник
std::for_each
я бы ожидал, что диапазон, основанный на цикле, будет лучшей заменой, чем обычныйfor
.std::for_each
, а не с диапазоном . Я удалил его, чтобы избежать путаницы.std::for_each()
. Когда у вас есть лямбда, это, конечно, лучше, чем традиционныйfor
цикл. Сfor
циклом, основанным на диапазоне, это может быть не так, но вы не написали «for
цикл на основе диапазона ».for
цикл» включает в себя «for
цикл на основе диапазона ». Я отредактировал с большим количеством объяснений и примером, чтобы прояснить, спасибо.В качестве отправной точки:
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
Всегда используйте алгоритмы и необработанное «для», так как это избавляет других от тщательного чтения вашего цикла, чтобы сделать вывод, что вы фактически выполняете итерацию по всей коллекции и т. Д. Если ваш компилятор поддерживает «диапазон для», то используйте его сноваfor_each
. Learn тривиальных вызовов алгоритма , какiota
,generate
,accumulate
,find_if
и так далее.Не слишком задумывайтесь о том, какой компилятор использовать. «Ужасный, ужасный» недостаток поддержки C ++ 11 в VS2012 состоит в том, что нет шаблонов с переменными параметрами (да, вы только что собирались использовать шаблоны с переменными параметрами), а
{}
инициализатор отсутствует. Я тоже этого хочу, но вряд ли перестану использовать полезный инструмент разработки.Второе, что нужно сделать после принятия
std::
- начать думать о RAII. В любое время у вас естьТогда у вас есть конструктор, несколько функций-членов и деструктор. Напишите класс, который позаботится об этом для вас. Возможно, вам даже не придется писать ctor и dtor. Помещение
shared_ptr
переменной-члена в класс является примером RAII - вы не пишете код управления памятью, но когда ваш экземпляр выходит из области видимости, происходят правильные вещи. Разверните, что на ваших глазах такие вещи, как закрытие файлов, освобождение дескрипторов, блокировок и т. Д., Станут проще и меньше (при этом устраняются утечки).Если вы чувствуете себя по-настоящему уверенно, сделайте чистку
printf
в пользуcout
, избавьтесь от макросов (#define
вещей) и начните изучать некоторые «продвинутые идиомы», такие как PIMPL. У меня есть целый курс по этому вопросу в Pluralsight, который вы, вероятно, можете посмотреть, используя их бесплатную пробную версию.источник
По программированию. Опыт - лучший способ учиться.
В C ++ 11 появилось много новых функций (auto, rvalue, новые умные указатели - это только некоторые из них). Лучше всего начать с их использования и читать о них, когда вы можете, и когда вы найдете интересную статью.
Это зависит от того, что вам нужно сделать. Большинство приложений могут обходиться без умных указателей и забыть об управлении памятью. Есть еще приложения, которые не могут так легко уйти (например, если им нужно новое размещение или пользовательский распределитель памяти по какой-либо причине).
Если вам нужно использовать Qt, вам придется использовать их правила для управления памятью.
Все, что у вас есть под рукой, поддерживает последний стандарт:
но ни один компилятор не поддерживает все функции.
источник
Мой университет все еще использует C ++ для обучения. Я программировал на C ++ в течение 5 лет и теперь я аспирант. Конечно, сейчас я использую Java, Ruby и т. Д. Я действительно рекомендую вам не слишком торопиться с такими функциями в языке, как Java. По моему опыту и мнению, после функций низкого уровня C ++. Вы должны изучить такие темы, как общее программирование на C / C ++, как создание шаблонного класса, шаблонные функции, переопределение операторов, виртуальные методы, умные указатели. В части объектно-ориентированного проектирования есть много функций, которые есть в C ++, а в Java нет, например, множественное наследование. Наследование является мощным, но и опасным. Уровень реализации объектно-ориентированного дизайна в C ++ также является хорошей темой. Межпроцессное взаимодействие, потоки также важны в C ++.
Для компилятора и отладчика. Я знаю, что визуальная студия великолепна. Но я действительно рекомендую вам изучать GDB, Valgrind и Make still, и хорошо разбираться в этих инструментах. Microsoft - это круто, но она сделала для тебя слишком много вещей. Будучи студентом, вы действительно должны изучить те вещи, которые Microsoft сделала для вас тоже. Для компилятора G ++ хорош из GNU.
В конце концов, после стольких лет, я действительно чувствую, самые важные вещи - это низкоуровневые функции, такие как необработанный массив. Вектор действительно просто динамический массив. Это мои рекомендации, возможно, слишком субъективные, просто примите то, что считаете правильным.
источник