Какие идиомы C ++ устарели в C ++ 11? - PullRequest
189 голосов
/ 15 февраля 2012

С новым стандартом появляются новые способы ведения дел, и многие из них приятнее старых, но старый способ все еще в порядке.Также ясно, что новый стандарт официально не очень устарел по причинам обратной совместимости.Таким образом, остается вопрос:

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

Отвечая на это, вы можете пропуститьочевидные вещи, такие как «использовать авто переменные».

Ответы [ 9 ]

171 голосов
/ 18 февраля 2012
  1. Final Class : C ++ 11 предоставляет спецификатор final для предотвращения вывода класса
  2. C ++ 11 лямбда-выражений существенно сокращают потребность в именованном объекте функции (функторе)) классы.
  3. Конструктор перемещения : Волшебные способы работы std::auto_ptr больше не нужны благодаря первоклассной поддержке ссылок на rvalue.
  4. Safe bool : это было упомянуто ранее.Явные операторы C ++ 11 устраняют эту очень распространенную идиому C ++ 03.
  5. Сокращение до соответствия : многие контейнеры C ++ 11 STL предоставляют функцию-член shrink_to_fit(),что должно исключить необходимость замены временным.
  6. Временный базовый класс : некоторые старые библиотеки C ++ используют эту довольно сложную идиому.С семантикой перемещения она больше не нужна.
  7. Тип Safe Enum Перечисления очень безопасны в C ++ 11.
  8. Запрещение выделения кучи :Синтаксис = delete - это гораздо более прямой способ сказать, что определенная функциональность явно запрещена.Это применимо для предотвращения выделения кучи (т. Е. =delete для элемента operator new), предотвращения копирования, назначения и т. Д.
  9. Templated typedef : Шаблоны псевдонимов в C ++ 11 уменьшена потребность в простых шаблонных определениях типов.Однако для генераторов сложного типа по-прежнему нужны мета-функции.
  10. Некоторые численные вычисления во время компиляции, такие как Фибоначчи, можно легко заменить, используя обобщенные константные выражения
  11. result_of: Использование шаблона класса result_of следует заменить на decltype.Я думаю, result_of использует decltype, когда он доступен.
  12. Инициализаторы членов класса сохраняют типизацию для инициализации по умолчанию нестатических членов со значениями по умолчанию.
  13. В новом C ++ 11 код NULL должен быть переопределен как nullptr, но см. выступление STL , чтобы узнать, почему они решили это сделать.
  14. Шаблон выражения фанатики рады иметь синтаксис функции trailing return в C ++ 11.Нет больше 30-строчных возвращаемых типов!

Думаю, на этом я остановлюсь!

65 голосов
/ 15 февраля 2012

В какой-то момент утверждалось, что нужно возвращать значение const вместо простого значения:

const A foo();
^^^^^

Это было в основном безвредно в C ++ 98/03 и может иметьдаже поймал несколько ошибок, которые выглядели так:

foo() = a;

Но возвращение на const противопоказано в C ++ 11, потому что оно запрещает семантику перемещения:

A a = foo();  // foo will copy into a instead of move into it

Так что просто расслабьтесь икод:

A foo();  // return by non-const value
61 голосов
/ 16 февраля 2012

Как только вы можете отказаться от 0 и NULL в пользу nullptr, сделайте это!

В не универсальном коде использование 0 или NULL не таковобольшое делоНо как только вы начинаете передавать константы нулевого указателя в универсальном коде, ситуация быстро меняется.Когда вы передаете 0 в template<class T> func(T) T, получается как int, а не как константа нулевого указателя.И после этого он не может быть преобразован обратно в константу нулевого указателя.В результате возникают проблемы, которых просто не существует, если в юниверсе используется только nullptr.

C ++ 11 не заменяет 0 и NULL как константы нулевого указателя.Но вы должны кодировать, как если бы это было.

38 голосов
/ 16 февраля 2012

идиома Safe bool explicit operator bool().

Конструкторы закрытых копий (boost :: noncopyable) → X(const X&) = delete

Имитация конечного класса с помощью частного деструктора и виртуального наследования class X final

24 голосов
/ 15 февраля 2012

Одна из вещей, которая просто заставляет вас избегать написания базовых алгоритмов на C ++ 11, - это доступность лямбд в сочетании с алгоритмами, предоставляемыми стандартной библиотекой.

Я использую их сейчас, и невероятно, как часто вы просто говорите, что хотите сделать, используя count_if (), for_each () или другие алгоритмы вместо того, чтобы снова писать чертовы циклы.

Как только вы используете компилятор C ++ 11 с полной стандартной библиотекой C ++ 11, у вас больше нет веских оправданий для того, чтобы не использовать стандартные алгоритмы для построения . Лямбда просто убей это.

Почему?

На практике (после того, как я сам использовал этот способ написания алгоритмов), гораздо проще читать что-то, построенное с простыми словами, означающими, что сделано, чем с некоторыми циклами, которые вы должны расшифровать, чтобы узнать значение. Тем не менее, автоматическое определение лямбда-аргументов очень поможет сделать синтаксис более простым для сравнения с необработанным циклом.

По сути, алгоритмы чтения, созданные с помощью стандартных алгоритмов, намного проще, чем слова, скрывающие детали реализации циклов.

Я предполагаю, что теперь нужно думать только об алгоритмах более высокого уровня, поскольку у нас есть алгоритмы более низкого уровня, на которых можно строить.

10 голосов
/ 16 февраля 2012

Вам нужно будет реализовывать пользовательские версии swap реже. В C ++ 03 часто требуется эффективный не-бросающий swap, чтобы избежать дорогостоящих и выбрасывающих копий, а поскольку std::swap использует две копии, swap часто приходится настраивать. В C ++ std::swap использует move, и поэтому акцент смещается на реализацию эффективных и не бросающих конструкторов перемещения и операторов присваивания перемещения. Поскольку для них по умолчанию часто просто отлично, это будет гораздо меньше работы, чем в C ++ 03.

Как правило, трудно предсказать, какие идиомы будут использоваться, так как они созданы на основе опыта. Мы можем ожидать «Эффективный C ++ 11», возможно, в следующем году, и «Стандарты кодирования C ++ 11» только через три года, потому что необходимого опыта еще нет.

2 голосов
/ 11 октября 2013

Я не знаю его имени, но код C ++ 03 часто использовал следующую конструкцию в качестве замены отсутствующего назначения перемещения:

std::map<Big, Bigger> createBigMap(); // returns by value

void example ()
{
  std::map<Big, Bigger> map;

  // ... some code using map

  createBigMap().swap(map);  // cheap swap
}

Это позволило избежать любого копирования из-за исключения копирования в сочетании сswap выше.

1 голос
/ 26 февраля 2016

Возврат по значению больше не проблема. С семантикой перемещения и / или оптимизацией возвращаемого значения (в зависимости от компилятора) функции кодирования более естественны без затрат и затрат (большую часть времени).

1 голос
/ 18 апреля 2015

Когда я заметил, что компилятор, использующий стандарт C ++ 11, больше не нарушает следующий код:

std::vector<std::vector<int>> a;

для предположительно содержащего оператора >>, я начал танцевать.В более ранних версиях нужно было бы сделать

std::vector<std::vector<int> > a;

Чтобы еще больше усугубить ситуацию, если вам когда-либо приходилось отлаживать это, вы знаете, насколько ужасны сообщения об ошибках, которые появляются из этого.

Я, однако, не знаю, было ли это «очевидным» для вас.

...