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


227

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

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


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 изменилось.


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и т.д. в качестве идентификаторов , то вы можете быть в беде ...


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.


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;
};

Если к стандартным библиотечным объектам добавлены явные преобразования, существующие неявные преобразования могут перестать работать. Но я не могу представить сценарий, когда преобразование не будет действительным и сделает что-то полезное.
— Деннис Зикефуз

Введение является серьезным изменением, потому что оно собирается заменить существующее 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

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

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

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


Результатом этих обсуждений является то, что он был удален почти во всех случаях. Есть ли проблемы с тем, что осталось?
— Деннис Зикефуз

@ Денис: Да. Ваш вопрос уже задавался,
— Бен Фойгт

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