Какие критические изменения введены в C ++ 11?

227

Я знаю, что, по крайней мере, одно из изменений в C ++ 11, которое приведет к тому, что старый код перестанет компилироваться: введение explicit operator bool()в стандартную библиотеку, замена старых экземпляров operator void*(). Конечно, код, который это нарушит, - это, вероятно, код, который в первую очередь не должен был быть действительным, но, тем не менее, это является серьезным изменением: программы, которые раньше были действительными, больше не являются.

Есть ли другие переломные изменения?

R. Martinho Fernandes
источник
1
Удалить значение exportключевого слова? Я принесу мне пальто.
Стив Джессоп
7
Вы знаете, я бы не назвал это изменение преобразования в бул «переломным изменением» ... больше похоже на «карающее изменение».
Xeo
4
Когда все документы, необходимые для создания такого союза, просто ждут штамповки, конечно, почему бы и нет?
Деннис Зикефуз
3
@Xeo: mystream.good()это не то же самое, что bool(mystream)? good()Значение true, если флаг не установлен. bool(mystream)все еще ложь, если только eofbitустановлен. !mystream.fail()будет правильным эквивалентом.
Р. Мартиньо Фернандес
2
Примечание для модератора : « Пожалуйста, оставляйте комментарии по теме с вопросом или ответом под рукой. При обсуждении вопроса или ответа речь должна идти только об этом, о вопросе или ответе под рукой. Дискуссия, как правило, не конструктивна для переполнения стека. Антагонизма, безусловно, нет. "
Тим Пост

Ответы:

178

В FDIS есть раздел о несовместимостях, в приложении C.2«C ++ и ISO C ++ 2003».

Резюме, перефразируя FDIS здесь, чтобы сделать его (лучше) пригодным в качестве SO ответа. Я добавил несколько собственных примеров, чтобы проиллюстрировать различия.

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

Основной язык


#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"

#define _x "there"
"hello"_x // now a user-defined-string-literal. Previously, expanded _x .

Новые ключевые слова: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert и thread_local


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


Действительный код C ++ 2003, который использует целочисленное деление, округляет результат до 0 или до отрицательной бесконечности, тогда как C ++ 0x всегда округляет результат до 0.

(по общему признанию не действительно проблема совместимости для большинства людей).


Допустимый код C ++ 2003, который использует ключевое слово autoв качестве спецификатора класса хранения, может быть недопустимым в C ++ 0x.


Сужающиеся преобразования вызывают несовместимости с C ++ 03. Например, следующий код действителен в C ++ 2003, но недопустим в этом международном стандарте, поскольку преобразование double в int является сужающим преобразованием:

int x[] = { 2.0 };

Неявно объявленные специальные функции-члены определяются как удаленные, если неявное определение было бы неправильно сформировано.

Действительная программа на C ++ 2003, которая использует одну из этих специальных функций-членов в контексте, где определение не требуется (например, в выражении, которое потенциально не оценивается), становится плохо сформированным.

Пример от меня:

struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }

Такой размер трюков использовался некоторыми SFINAE, и теперь его нужно изменить :)


Объявленные пользователем деструкторы имеют неявную спецификацию исключений.

Пример от меня:

struct A {
  ~A() { throw "foo"; }
};

int main() { try { A a; } catch(...) { } }

Этот код вызывает terminateв C ++ 0x, но не в C ++ 03. Потому что неявная спецификация исключения A::~Aв C ++ 0x есть noexcept(true).


Действительное объявление C ++ 2003, содержащее exportнеправильную форму в C ++ 0x.


Допустимое выражение C ++ 2003, содержащее >сразу после другого, >теперь может рассматриваться как закрывающее два шаблона.

В C ++ 03 >>всегда будет токен оператора сдвига.


Разрешить зависимые вызовы функций с внутренней связью.

Пример от меня:

static void f(int) { }
void f(long) { }

template<typename T>
void g(T t) { f(t); }

int main() { g(0); }

В C ++ 03 это вызывает f(long), но в C ++ 0x это вызывает f(int). Следует отметить, что как в C ++ 03, так и в C ++ 0x выполняются следующие вызовы f(B)(контекст экземпляра все еще рассматривает только объявления внешних связей).

struct B { };
struct A : B { };

template<typename T>
void g(T t) { f(t); }

static void f(A) { }
void f(B) { }

int main() { A a; g(a); }

Лучшее соответствие f(A)не берется, потому что оно не имеет внешней связи.


Изменения в библиотеке

Действительный код C ++ 2003, который использует любые идентификаторы, добавленные в стандартную библиотеку C ++ C ++ 0x, может не скомпилироваться или привести к другим результатам в этом международном стандарте.


Допустимый код C ++ 2003, в котором #includesзаголовки с именами новых заголовков стандартной библиотеки C ++ 0x могут быть недопустимыми в этом международном стандарте.


Действительный код C ++ 2003, который был скомпилирован, ожидая, что своп должен быть, <algorithm>может вместо этого включать<utility>


Глобальное пространство имен posixтеперь зарезервировано для стандартизации.


Действительный C ++ 2003 код , который определяет override, final, carries_dependencyили noreturnкак макросы недопустим в C ++ 0x.

оборота Йоханнес Шауб - лит
источник
«Разрешить зависимые вызовы функций с внутренней связью». Не могли бы вы пояснить разницу между вашими двумя примерами? Я явно что-то упускаю.
Деннис Зикефуз
@Dennis изменение было представлено open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 . Хотя они не комментируют этот факт, «контекст создания» все еще состоит только из «набора объявлений с внешней связью, объявленных до момента создания специализации шаблона в том же модуле перевода». Таким образом, сделанные ими изменения влияют только на поиск в контексте определения.
Йоханнес Шауб -
В моем первом приведенном примере функция внутренних связей была видна и находилась в контексте определения шаблона. Во втором примере внутренняя функция связи должна быть частью контекста создания, который нужно найти. Но так как это не так, его нельзя найти.
Йоханнес Шауб -
Между прочим, я думаю, что единственный случай, когда для контекста определения шаблона безопасно найти функцию с внутренней связью, - это когда специализация шаблона функции создается только в явном виде, создается в одном TU (где определен шаблон), а все другие TU полагаются на это явное воплощение. Во всех других случаях (когда другие TU сами создают экземпляр специализации), вы нарушаете ODR, если в определении шаблона каждый раз используется другая (внутренняя связь) функция.
Йоханнес Шауб -
Поэтому я не уверен, почему они сохранили ограничение на контекст создания экземпляра - будет только один (явный) экземпляр, и этот экземпляр будет использовать внутренние функции связывания, найденные в контексте создания экземпляра TU. Так же, как это было бы для определения контекста. Между прочим, я думаю, что если бы мы все еще имели export, то я думаю, что другие TU не должны были бы полагаться на явное создание экземпляра, но могли бы сами создать экземпляр шаблона. Тогда будет иметь значение, будут ли внутренние контекстные функции видны в контексте реализации.
Йоханнес Шауб -
28

Значение ключевого слова auto изменилось.

arsenm
источник
9
Если вы использовали autoключевое слово, что-то не так с вашим кодом. С какой стати ты это использовал?
Элазар Лейбович
Это не серьезное изменение . Каждое допустимое использование C ++ 03 autoостается действительным в C ++ 11.
Дрю Дорманн
11
@DrewDormann int main() { auto int i = 0; return i; }совершенно корректно C ++ 03, но синтаксическая ошибка в C ++ 11. Единственное предупреждение, которое я могу получить от компиляторов в режиме C ++ 03, - это предупреждение о совместимости.
24

Срочные перемены?

Ну, во - первых, если вы использовали decltype, constexpr, nullptrи т.д. в качестве идентификаторов , то вы можете быть в беде ...

Downvoter
источник
21

Некоторые основные несовместимости, которые не охвачены разделом несовместимости:


C ++ 0x обрабатывает введенное имя класса как шаблон, если имя передается в качестве аргумента параметра шаблона, и как тип, если оно передается параметру типа шаблона.

Действительный код C ++ 03 может вести себя по-разному, если он полагается, что введенное имя класса всегда будет типом в этих сценариях. Пример кода взят из моего пиара

template<template<typename> class X>
struct M { };

template<template<typename> class X>
void g(int = 0); // #1

template<typename T>
void g(long = 0); // #2

template<typename T>
struct A {
  void f() {
    g<A>(); /* is ambiguous in C++0x */
    g<A>(1); /* should choose #1 in C++0x */
  }
};

void h() {
  A<int> a;
  a.f();
}

В C ++ 03 код вызывает второй gраз оба раза.


C ++ 0x делает некоторые имена, которые были зависимы в C ++ 03, теперь не зависимыми. И требует, чтобы поиск по имени для независимых независимых квалифицированных имен, которые ссылаются на члены текущего шаблона класса, повторялись при создании экземпляра, и требует проверки того, что эти имена ищут так же, как это делается в контексте определения шаблона.

Действительный код C ++ 03, который зависит от правила доминирования, может больше не компилироваться из-за этого изменения.

Пример:

struct B { void f(); };

template<typename T>
struct A : virtual B { void f(); };

template<typename T>
struct C : virtual B, A<T> {
  void g() { this->f(); }
};

int main() { C<int> c; c.g(); }

Этот действительный код C ++ 03, который вызывает A<int>::f, недопустим в C ++ 0x, потому что поиск имени при создании экземпляра будет обнаружен, A<int>::fа не B::fвызовет конфликт с поиском по определению.

На данный момент не ясно, является ли это дефектом в FDIS. Комитет знает об этом и оценит ситуацию.


Объявление using, в котором последняя часть совпадает с идентификатором в последней части квалификатора в квалифицированном имени, обозначающем базовый класс, при использовании объявления теперь именуется конструктор, а не члены с таким именем.

Пример:

struct A { protected: int B; };
typedef A B;

struct C : B {
  // inheriting constructor, instead of bringing A::B into scope
  using B::B;
};

int main() { C c; c.B = 0; }

Приведенный выше пример кода хорошо сформирован в C ++ 03, но плохо сформирован в C ++ 0x, так как A::Bдо сих пор недоступен в main.

Johannes Schaub - litb
источник
14

Ошибка извлечения потока обрабатывается по-разному.

пример

#include <sstream>
#include <cassert>

int main()
{
   std::stringstream ss;
   ss << '!';
   
   int x = -1;
   
   assert(!(ss >> x)); // C++03 and C++11
   assert(x == -1);    // C++03
   assert(x == 0);     // C++11
}

Изменить предложение

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23

Стандартная ссылка

[C++03: 22.2.2.1.2/11]: Результатом этапа 2 обработки может быть один из

  • Последовательность символов была накоплена на этапе 2, которая преобразуется (в соответствии с правилами scanf) в значение типа val. Это значение хранится в valи ios_base::goodbitхранится в err.
  • Последовательность символов, накопленная на этапе 2, вызвала scanfбы сообщение об ошибке ввода. ios_base::failbitназначен на err. [ed: Ничего не хранится в val.]

[C++11: 22.4.2.1.2/3]: [..] Числовое значение, которое будет сохранено, может быть одним из:

  • ноль, если функция преобразования не может преобразовать все поле . ios_base::failbitназначен на err.
  • наиболее положительное представимое значение, если поле представляет слишком большое положительное значение, чтобы быть представленным в val. ios_base::failbitназначен на err.
  • самое отрицательное представимое значение или ноль для целого типа без знака, если поле представляет значение, слишком большое отрицательное, чтобы быть представленным в val. ios_base::failbitназначен на err.
  • преобразованное значение, в противном случае.

Полученное числовое значение сохраняется в val.

Реализации

  • GCC 4.8 правильно выводит для C ++ 11 :

    Утверждение `x == -1 'не удалось

  • GCC 4.5-4.8 все выводит для C ++ 03 следующее, что может показаться ошибкой:

    Утверждение `x == -1 'не удалось

  • Visual C ++ 2008 Express правильно выводит для C ++ 03:

    Ошибка подтверждения: x == 0

  • Visual C ++ 2012 Express неправильно выводит для C ++ 11, что может показаться проблемой состояния реализации:

    Ошибка подтверждения: x == 0

Гонки Легкости на Орбите
источник
13

Как введение операторов явного преобразования является переломным изменением? Старая версия по-прежнему будет такой же «действительной», как и раньше.

Да, изменение с operator void*() constна explicit operator bool() constбудет критическим изменением, но только в том случае, если оно используется неправильно и само по себе. Соответствующий код не будет нарушен.

Теперь еще одно серьезное изменение - запрет сужающих конверсий во время инициализации агрегата :

int a[] = { 1.0 }; // error

Редактировать : просто запомнить, std::identity<T>будет удален в C ++ 0x (см. Примечание). Это удобная структура, чтобы сделать типы зависимыми. Поскольку структура на самом деле ничего не делает, это должно исправить это:

template<class T>
struct identity{
  typedef T type;
};
Xeo
источник
Если к стандартным библиотечным объектам добавлены явные преобразования, существующие неявные преобразования могут перестать работать. Но я не могу представить сценарий, когда преобразование не будет действительным и сделает что-то полезное.
Деннис Зикефуз
Введение является серьезным изменением, потому что оно собирается заменить существующее operator void*.
Р. Мартиньо Фернандес
@Dennis: Ааа, теперь я понимаю, что имел в виду @Martinho. Но это будет серьезное изменение, если люди будут использовать его не по назначению.
Xeo
«но только если оно используется таким образом, что это неправильно и само по себе» - bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }в этом нет ничего действительно плохого в C ++ 03, но это стало ошибкой в ​​C ++ 11. (Примечание: GCC 4.9 все еще operator void*() constздесь, поэтому он принимает код в режиме C ++ 11.)
std::identity<T>не был удален в C ++ 11, потому что он не был частью C ++ 03. Он кратко существовал в проекте для C ++ 11 и был удален из проекта до стандартизации.
Говард Хиннант,
8

В библиотеку контейнеров внесены многочисленные изменения, которые обеспечивают более эффективный код, но бесшумно нарушают обратную совместимость для нескольких ключевых случаев.

Рассмотрим, например, std::vectorконструкцию по умолчанию, C ++ 0x и внесение изменений .

оборота Джеймс МакНеллис
источник
7

Было много дискуссий о неявном движении, нарушающем обратную совместимость

( старая страница с соответствующим обсуждением )

Если вы читаете в комментариях, неявный возврат хода также является серьезным изменением.

Ben Voigt
источник
Результатом этих обсуждений является то, что он был удален почти во всех случаях. Есть ли проблемы с тем, что осталось?
Деннис Зикефуз
@ Денис: Да. Ваш вопрос уже задавался,
Бен Фойгт
Ах, на мобильной странице не было комментариев. В любом случае, это гораздо более полезная ссылка ... Исторические странности процесса стандартизации не так уж актуальны (если только вы не используете MSVC, который, как мне кажется, использует этот первый черновик).
Деннис Зикефуз
@ Денис: я думаю, что ты прав. Перемещены ссылки вокруг некоторых в моем ответе.
Бен Фойгт
К сожалению, cpp-next.com больше не существует. Для дальнейшего использования это страницы, сохраненные web.archive.org: неявное перемещение, нарушающее обратную совместимость, и более старая страница с соответствующим обсуждением .
Макс Трукса
6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03: действителен

C ++ 0x: error: parameter declared 'auto'

Гонки легкости на орбите
источник
2
@Xeo: код действителен в C ++ 03. Это параметр с типом struct xи без имени.
Бен Фойгт
Я надеялся поймать кого-нибудь. Жаль только, что @Xeo не так быстро удалил свой комментарий, так как я не смог его прочитать!
Гонки легкости на орбите
@Xeo: Не копаясь в грамматике, я уверен, что auto просто не является допустимым ключевым словом. Если бы это было так, это, вероятно, сработало бы так, как вы ожидаете, но это, вероятно, очень сложно определить правильно.
Деннис Зикефуз
Скажем так, ты поймал меня. Он буквально игнорировал структуру. :)
Xeo
@Tomalek: Xeo справедливо указал, что C ++ 03 не имеет неявного int.
Бен Фойгт
-4

Особенности языка

  1. Равномерная и общая инициализация с использованием {}
  2. авто
  3. Предотвращение сужения
  4. constexpr
  5. Диапазон на основе цикла
  6. nullptr
  7. enum class
  8. static_assert
  9. станд :: initializer_list
  10. Rvalue ссылки (переместить семантику)
  11. >>
  12. Лямбда
  13. Вариативные шаблоны
  14. Тип и шаблон псевдонимов
  15. Символы Юникод
  16. тип long long integer
  17. alignas и alignof
  18. decltype
  19. Необработанные строковые литералы
  20. Обобщенный POD
  21. Обобщенные союзы
  22. Локальные классы как аргументы шаблона
  23. Суффикс возвращаемого типа синтаксиса
  24. [[carry_dependency]] и [[noreturn]]
  25. нет, кроме спецификатора
  26. нет, кроме оператора.
  27. Особенности C99:
    • расширенные целочисленные типы
    • объединение узкой / широкой струны
    • _ _ STDC_HOSTED _ _
    • _Pragma (Х)
    • макросы vararg и пустые аргументы макроса
  28. _ _ func _ _
  29. Встроенные пространства имен
  30. Делегирующие конструкторы
  31. Инициализаторы членов класса
  32. по умолчанию и удалить
  33. Операторы явного преобразования
  34. Пользовательские литералы
  35. Внешние шаблоны
  36. Аргументы шаблона по умолчанию для шаблонов функций
  37. Наследование конструкторов
  38. переопределить и окончательно
  39. Простое и более общее правило SFINAE
  40. Модель памяти
  41. thread_local

Стандартные библиотечные компоненты

  1. initializer_list для контейнеров
  2. Переместить семантику для контейнеров
  3. forward_list
  4. Хэш-контейнеры
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. Указатели управления ресурсами
    • unique_ptr
    • shared_ptr
    • weak_ptr
  6. Поддержка параллелизма
    • нить
    • мьютексы
    • замки
    • переменные условия
  7. Поддержка параллелизма более высокого уровня
    • packaged_thread
    • будущее
    • обещание
    • асинхронной
  8. кортежи
  9. регулярное выражение
  10. Случайные числа
    • uniform_int_distribution
    • нормальное распределение
    • random_engine
    • и т.п.
  11. Целочисленные имена типов, такие как int16_t, uint32_t и int_fast64_t
  12. массив
  13. Копирование и сброс исключений
  14. системная ошибка
  15. emplace () операции для контейнеров
  16. функции constexpr
  17. Систематическое использование неисключительных функций
  18. функционировать и связывать
  19. Преобразование строки в числовое значение
  20. Распределители
  21. Тип черты
  22. Утилиты времени: продолжительность и время
  23. соотношение
  24. quick_exit
  25. Дополнительные алгоритмы, такие как move (), copy_if () и is_sorted ()
  26. Сборка мусора ABI
  27. атомная энергетика

Устаревшие Особенности

  1. Генерация конструктора копирования и назначение копирования для класса с деструктором.
  2. Присвойте строковый литерал символу *.
  3. Спецификация исключения C ++ 98
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • неожиданный
  4. Функциональные объекты и связанные функции
  5. auto_ptr
  6. регистр
  7. ++ на бул
  8. экспорт
  9. Кастинги в стиле C
оборота мустафагонул
источник
3
Это не отвечает на вопрос.