Какие критические изменения введены в 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.
Срочные перемены?
Ну, с одной стороны, если вы использовали 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'
Особенности языка
- Равномерная и общая инициализация с использованием {}
- авто
- Предотвращение сужения
- constexpr
- Диапазон на основе цикла
- nullptr
- enum class
- static_assert
- станд:: initializer_list
- Rvalue ссылки (переместить семантику)
>>
- Лямбда
- Variadic шаблоны
- Тип и шаблон псевдонимов
- Символы Юникода
- тип long long integer
- alignas и alignof
- decltype
- Необработанные строковые литералы
- Обобщенный POD
- Обобщенные союзы
- Локальные классы как аргументы шаблона
- Суффикс возвращаемого типа синтаксиса
- [[carry_dependency]] и [[noreturn]]
- нет, кроме спецификатора
- нет, кроме оператора.
- Особенности 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
- Поддержка параллелизма
- нить
- мьютексы
- замки
- переменные условия
- Поддержка параллелизма более высокого уровня
- packaged_thread
- будущее
- обещание
- асинхронной
- кортежи
- регулярное выражение
- Случайные числа
- uniform_int_distribution
- нормальное распределение
- random_engine
- и т.п.
- Целочисленные имена типов, такие как int16_t, uint32_t и int_fast64_t
- массив
- Копирование и отбрасывание исключений
- системная ошибка
- emplace() операции для контейнеров
- функции constexpr
- Систематическое использование неисключительных функций
- функционировать и связывать
- Преобразование строки в числовое значение
- Распределители
- Тип черты
- Утилиты времени: продолжительность и время
- соотношение
- quick_exit
- Дополнительные алгоритмы, такие как move(), copy_if() и is_sorted()
- Сборка мусора ABI
- атомная энергетика
Устаревшие Особенности
- Генерация конструктора копирования и назначение копирования для класса с деструктором.
- Присвойте строковый литерал символу *.
- Спецификация исключения C++98
- unexcepted_handler
- set_unexpected
- get_unexpected
- неожиданный
- Функциональные объекты и связанные функции
- auto_ptr
- регистр
- ++ на бул
- экспорт
- Кастинги в стиле C