Какие нарушительные изменения внесены в С++ 11?

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

Есть ли какие-либо другие изменения?

Ответы

Ответ 1

В FDIS есть раздел для несовместимости, в приложении C.2 "С++ и ISO С++ 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


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


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

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


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


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

int x[] = { 2.0 };

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

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

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

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

Подобные трюки sizeof используются некоторыми SFINAE, и их необходимо изменить сейчас:)


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

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

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

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

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


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


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

В С++ 03, >> всегда будет токеном оператора shift.


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

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

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

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

int main() { g(0); }

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

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) не выполняется, поскольку оно не имеет внешней привязки.


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

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


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


Действительный код С++ 2003, который был скомпилирован, ожидая, что swap будет находиться в <algorithm>, возможно, должен включать <utility>


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


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

Ответ 2

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

Ответ 3

Нарушение изменений?

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

Ответ 4

Некоторые основные несовместимости, которые не охватываются секцией несовместимости:


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

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

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

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


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

Действительный код С++ 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(); }

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

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


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

Пример:

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

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

Ответ 5

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

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

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

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

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

template<class T>
struct identity{
  typedef T type;
};

Ответ 6

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

Пример

#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 правильно выводит для С++ 11:

    Утверждение `x == -1 'не выполнено

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

    Утверждение `x == -1 'не выполнено

  • Visual С++ 2008 Express корректно выдает для С++ 03:

    Утверждение не выполнено: x == 0

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

    Утверждение не выполнено: x == 0

Ответ 7

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

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

Ответ 9

struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

С++ 03:.

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

Ответ 10

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

  • Унифицированная и общая инициализация с использованием {}
  • авто
  • Предотвращение сужения
  • constexpr
  • Диапазон, основанный на цикле
  • nullptr
  • класс enum
  • static_assert
  • станд:: initializer_list
  • Ссылки Rvalue (семантика перемещения)
  • >>
  • Лямбда
  • Шаблоны Variadic
  • Имена типов и шаблонов
  • Юникодовые символы
  • длинный целочисленный тип
  • alignas и alignof
  • decltype
  • Строковые литералы
  • Обобщенный POD
  • Обобщенные союзы
  • Локальные классы как аргументы шаблона
  • Синтаксис типа возврата суффикса
  • [[carry_dependency]] и [[noreturn]]
  • спецификатор noexcept
  • оператор noexcept.
  • Функции C99:
    • расширенные интегральные типы
    • конкатенация узкой/широкой строки
    • _ _ STDC_HOSTED _ _
    • _Pragma (Х)
    • макросы vararg и пустые аргументы макроса
  • _ _ func _ _
  • Внутренние пространства имен
  • Делегирующие конструкторы
  • Инициализаторы инициализации класса
  • по умолчанию и удаление
  • Явные операторы преобразования
  • Пользовательские литералы
  • Внешние шаблоны
  • Аргументы шаблона по умолчанию для шаблонов функций
  • Наследование конструкторов
  • переопределение и окончательный
  • Более простое и общее правило SFINAE
  • Модель памяти
  • thread_local

Компоненты стандартной библиотеки

  • initializer_list для контейнеров
  • Переместить семантику для контейнеров
  • forward_list
  • Контейнеры-контейнеры
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  • Указатели управления ресурсами
    • unique_ptr
    • shared_ptr
    • weak_ptr
  • Concurrency поддержка
    • поток
    • мьютексы
    • замки
    • переменные условия
  • Поддержка более высокого уровня concurrency
    • packaged_thread
    • будущее
    • обещание
    • асинхронной
  • кортежи
  • регулярное выражение
  • Случайные числа
    • uniform_int_distribution
    • normal_distribution
    • random_engine
    • и др.
  • Имена типа целочисленного типа, такие как int16_t, uint32_t и int_fast64_t
  • массив
  • Копирование и повторное удаление исключений
  • system_error Операции
  • emplace() для контейнеров
  • функции constexpr
  • Систематическое использование функций noexcept
  • функция и привязка
  • Преобразование строк в числовые значения
  • Ограниченные распределители
  • Типовые черты
  • Утилиты времени: продолжительность и время_point
  • соотношение
  • quick_exit
  • Дополнительные алгоритмы, такие как move(), copy_if() и is_sorted()
  • Сбор мусора ABI
  • атомарных

Устаревшие функции

  • Генерация конструктора копирования и назначение копии для класса с деструктором.
  • Назначьте строковый литерал char *.
  • Спецификация исключения С++ 98
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • неожиданное
  • Объекты функций и связанные с ними функции
  • auto_ptr
  • Регистр
  • ++ на bool
  • Экспорт
  • C-style casts