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

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

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

10 ответов

В 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.

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

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

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

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


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,

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

пример

#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

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

[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

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

Да, изменение от 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;
};

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

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

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

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

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

struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

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

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

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

  1. Равномерная и общая инициализация с использованием {}
  2. авто
  3. Предотвращение сужения
  4. constexpr
  5. Диапазон на основе цикла
  6. nullptr
  7. enum class
  8. static_assert
  9. станд:: initializer_list
  10. Rvalue ссылки (переместить семантику)
  11. >>
  12. Лямбда
  13. Variadic шаблоны
  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
Другие вопросы по тегам