Какие нарушительные изменения внесены в С++ 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 и нарушение изменений.
Ответ 8
Было много дискуссий о неявном движении, нарушающем обратную совместимость
(более старая страница с соответствующей дискуссией)
Если вы читаете в комментариях, неявный возврат движения также является нарушением изменений.
Ответ 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