С новым стандартом появляются новые способы ведения дел, и многие из них более хороши, чем старые, но старый способ все еще в порядке. Также ясно, что новый стандарт официально не очень устарел по причинам обратной совместимости. Итак, вопрос, который остается:
Какие старые способы кодирования определенно уступают стилям C ++ 11, и что мы можем теперь вместо этого делать?
Отвечая на это, вы можете пропустить очевидные вещи, такие как «использовать автоматические переменные».
auto_ptr
не рекомендуется.Ответы:
final
спецификатор для предотвращения деривации классаstd::auto_ptr
работы больше не нужны из-за первоклассной поддержки ссылок на rvalue.shrink_to_fit()
член, которая должна исключить необходимость замены на временную.= delete
Синтаксис - это гораздо более прямой способ сказать, что определенная функциональность явно запрещена. Это применимо для предотвращения выделения кучи (т.е.=delete
для членаoperator new
), предотвращения копирования, назначения и т. Д.result_of
: Использование шаблона классаresult_of
должно быть заменено наdecltype
. думаюresult_of
использует,decltype
когда это доступно.NULL
должен быть переопределен какnullptr
, но см. Доклад STL чтобы узнать, почему они решили отказаться от него.Я думаю, что я остановлюсь там!
источник
result_of
из списка. Несмотря на громоздкость,typename
необходимую перед этим, я думаю, чтоtypename result_of<F(Args...)::type
иногда легче читать, чемdecltype(std::declval<F>()(std::declval<Args>()...)
, и с принятием N3436 в рабочий документ они оба работают для SFINAE (что раньше было преимуществом тогоdecltype
,result_of
чего не предлагали)В какой-то момент утверждалось, что нужно возвращать по
const
значению, а не просто по значению:Это было в основном безвредно в C ++ 98/03 и, возможно, даже обнаружило несколько ошибок, которые выглядели так:
Но возврат
const
в C ++ 11 противопоказан, потому что он запрещает семантику перемещения:Так что просто расслабьтесь и код:
источник
A& operator=(A o)&
вместо определенияA& operator=(A o)
. Это предотвращает глупые ошибки и делает классы более похожими на базовые типы и не предотвращает семантику перемещения.Как только вы можете отказаться
0
иNULL
в пользуnullptr
, сделайте это!В неуниверсальном коде использование
0
илиNULL
не такое уж большое дело. Но как только вы начинаете передавать константы нулевого указателя в универсальном коде, ситуация быстро меняется. При переходе0
к atemplate<class T> func(T)
T
выводится какint
константа нулевого указателя, а не как. И после этого он не может быть преобразован обратно в константу нулевого указателя. Это переходит в болото проблем, которых просто не существует, если использовать только вселеннуюnullptr
.C ++ 11 не считается устаревшим
0
иNULL
является константой нулевого указателя. Но вы должны кодировать, как если бы это было.источник
std::nullptr_t
.0
илиNULL
для нулевых указателей»).Безопасный бул идиома →
explicit operator bool()
.Конструкторы частных копий (boost :: noncopyable) →
X(const X&) = delete
Имитация финального класса с частным деструктором и виртуальным наследованием →
class X final
источник
Одна из вещей, которая просто заставляет вас избегать написания базовых алгоритмов на C ++ 11, - это доступность лямбд в сочетании с алгоритмами, предоставляемыми стандартной библиотекой.
Я использую их сейчас, и невероятно, как часто вы просто говорите, что вы хотите сделать, используя count_if (), for_each () или другие алгоритмы вместо того, чтобы снова писать чертовы циклы.
Как только вы используете компилятор C ++ 11 с полной стандартной библиотекой C ++ 11, у вас больше нет веских оправданий, чтобы не использовать стандартные алгоритмы для построения своих . Лямбда просто убей это.
Зачем?
На практике (после того, как я сам использовал этот способ написания алгоритмов), гораздо проще читать что-то, построенное с простыми словами, означающими то, что сделано, чем с некоторыми циклами, которые вы должны расшифровать, чтобы узнать значение. Тем не менее, автоматическое определение лямбда-аргументов очень поможет сделать синтаксис более простым для сравнения с необработанным циклом.
По сути, алгоритмы чтения, сделанные с помощью стандартных алгоритмов, намного проще, чем слова, скрывающие детали реализации циклов.
Я предполагаю, что теперь нужно думать только об алгоритмах более высокого уровня, поскольку у нас есть алгоритмы более низкого уровня, на которых можно основываться.
источник
for_each
лямбда-код был лучше, чем эквивалентный цикл for, основанный на диапазоне, с содержанием лямбды в цикле. Код выглядит более или менее одинаково, но лямбда вводит дополнительную пунктуацию. Вы можете использовать эквиваленты таких вещей, какboost::irange
применять его к большему количеству циклов, чем те, которые явно используют итераторы. Плюс цикл for, основанный на диапазоне, обладает большей гибкостью, так как вы можете выйти досрочно, если это необходимо (в порядкеreturn
или на времяbreak
), тогда какfor_each
вам нужно будет бросить.for
делает обычнуюit = c.begin(), const end = c.end(); it != end; ++it
идиому несуществующей.for_each
алгоритма перед диапазоном, основанным на цикле, является то, что вы не можетеbreak
илиreturn
. То есть, когда вы видите,for_each
вы сразу же знаете, не глядя на тело, что такой хитрости нет.std::for_each(v.begin(), v.end(), [](int &i) { ++i; });
сfor (auto &i : v) { ++i; }
. Я принимаю, что гибкость обоюдоострая (goto
очень гибкая, вот в чем проблема). Я не думаю , что ограничение не в состоянии использоватьbreak
вfor_each
версии компенси- дополнительного многословия она требует - пользователиfor_each
здесь IMO жертвуя реально читаемость и удобство для своего рода теоретического понятия о том , чтоfor_each
это в принципе ясно и концептуально проще. На практике это не яснее и не проще.Вам нужно будет реализовывать пользовательские версии
swap
реже. В C ++ 03swap
часто необходим эффективный отказ от передачи , чтобы избежать дорогостоящих и бросающих копий, и, посколькуstd::swap
используются две копии,swap
часто приходится настраивать их. В C ++std::swap
используетmove
, и поэтому фокус смещается на реализацию эффективных и не вызывающих бросков конструкторов перемещения и операторов присваивания перемещения. Поскольку для них по умолчанию часто просто отлично, это будет гораздо меньше работы, чем в C ++ 03.Как правило, трудно предсказать, какие идиомы будут использоваться, так как они созданы на основе опыта. Мы можем ожидать «Эффективный C ++ 11», возможно, в следующем году, и «Стандарты кодирования C ++ 11» только через три года, потому что необходимого опыта еще нет.
источник
Я не знаю его имени, но код C ++ 03 часто использовал следующую конструкцию в качестве замены отсутствующего назначения перемещения:
Это позволило избежать копирования благодаря исключению копирования в сочетании с
swap
вышеизложенным.источник
map
любом случае. Техника, которую вы показываете, полезна, если онаmap
уже существует, а не просто создается. Пример был бы лучше без комментария «дешевый конструктор по умолчанию» и с «// ...» между этой конструкцией и свопомКогда я заметил, что компилятор, использующий стандарт C ++ 11, больше не нарушает следующий код:
для якобы содержащего оператора >> я начал танцевать. В более ранних версиях нужно было бы сделать
Что еще хуже, если вам когда-либо приходилось отлаживать это, вы знаете, насколько ужасны сообщения об ошибках, которые появляются из-за этого.
Я, однако, не знаю, было ли это "очевидным" для вас.
источник
Возврат по значению больше не проблема. С семантикой перемещения и / или оптимизацией возвращаемого значения (зависит от компилятора) функции кодирования более естественны без затрат и затрат (большую часть времени).
источник