Які переломні зміни вводяться в C ++ 11?


227

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

Чи є якісь інші зміни?


1
Видалення значення exportключового слова? Я дістану мені пальто.
Стів Джессоп

7
Знаєте, я б не називав це зміною конверсії в bool "проривною зміною" ... більше, як "караючою зміною".
Xeo

4
Коли всі документи, необхідні для створення такого союзу, просто чекають, коли вони будуть штамповані, звичайно, чому б і ні?
Dennis Zickefoose

3
@Xeo: mystream.good()це не те саме, що bool(mystream)? good()вірно, якщо прапор не встановлено. bool(mystream)все ще помилково, якщо тільки eofbitвстановлено. !mystream.fail()був би правильним еквівалентом.
Р. Мартиньо Фернандес

2
Примітка модератора : " Будь ласка, зберігайте коментарі до теми з питанням або відповіддю під рукою. Під час обговорення питання чи відповіді дискусія повинна бути саме такою, питанням або відповіддю під рукою. Дебати, як правило, не є конструктивними для переповнення стека. Антигонізувати, безумовно, немає. "
Tim Post

Відповіді:


178

У FDIS є розділ щодо несумісності у додатку C.2"C ++ та ISO C ++ 2003".

Короткий підсумок, перефразовуючи FDIS тут, щоб зробити його (кращим) придатним як відповідь ТА. Я додав кілька власних прикладів, щоб проілюструвати відмінності.

Є кілька несумісностей, пов’язаних з бібліотекою, де я точно не знаю наслідків, тому я залишаю їх іншим детальніше.

Основна мова


#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


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


Дійсний код C ++ 2003, який використовує ціле ділення, округляє результат до 0 або до негативної нескінченності, тоді як C ++ 0x завжди округляє результат до 0.

(правда, це не є проблемою сумісності для більшості людей).


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


Звуження конверсій спричиняє несумісність із C ++ 03. Наприклад, наступний код дійсний у C ++ 2003, але недійсний у цьому Міжнародному стандарті, оскільки подвійний до 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 >>завжди буде маркер оператора shift.


Дозволити залежні виклики функцій із внутрішнім зв’язком.

Приклад мною:

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 Zickefoose

@Денніс зміна була введена на сайті open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561 . Хоча вони і не коментують цього факту, "контекст інстанції" все ще складається лише з "набору декларацій із зовнішнім зв'язком, оголошених до моменту інстанціювання спеціалізації шаблону в тій же одиниці перекладу". Тож зміна, яку вони внесли, впливає лише на пошук у контексті визначення.
Йоханнес Шауб - ліб

У моєму першому прикладі наведена функція внутрішнього зв’язку була помітна і знайдена в контексті визначення шаблону. У моєму другому прикладі функція внутрішнього зв’язку повинна бути частиною контексту інстанції, який потрібно знайти. Але оскільки його немає, його неможливо знайти.
Йоханнес Шауб - ліб

Між іншим, я думаю, що єдиний випадок, коли в контексті визначення шаблону безпечно знайти функцію з внутрішнім зв’язком, - це коли спеціалізація шаблонів функцій лише явно інстанціюється інстанціюватися в одному TU (де визначено шаблон), і всі інші TU покладаються на що явна інстанція. У всіх інших випадках (коли інші TU мінятимуть спеціалізацію), ви б порушили ODR, маючи визначення шаблону кожен раз використовувати іншу (внутрішню зв'язок) функцію.
Йоханнес Шауб - ліб

Тож я не впевнений, чому вони дотримувались обмеження щодо контекстної інстанції - існувала б лише одна (явна) інстанція, і ця інстанція використовує функції внутрішніх зв'язків, що знаходяться в контексті інстанції інстанційного ТУ. Так само, як це було б для контексту визначення. Між іншим, я думаю, якби у нас все-таки існували export, я думаю, що іншим ТУ не потрібно було б покладатися на явну інстанцію, але вони могли б інстанціювати шаблони. Тоді було б важливо змінити, чи видимі функції внутрішнього зв’язку в контексті інстанції чи ні.
Йоханнес Шауб - ліб

28

Змінилося значення ключового слова авто.


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. Комітет знає про це і оцінить ситуацію.


Декларація, що використовує, де остання частина є такою ж, як ідентифікатор в останній частині класифікатора у кваліфікованому імені, що позначає базовий клас, та, використовуючи оголошення, тепер називає конструктор замість членів з цим ім'ям.

Приклад:

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. [ред .: Нічого не зберігається 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;
};

Якщо до стандартних об'єктів бібліотеки були додані явні перетворення, то наявні неявні перетворення можуть припинити роботу. Але я не можу уявити сценарій, коли конверсія не була б дійсною і робила щось корисне.
Dennis Zickefoose

Вступ є суттєвою зміною, оскільки він буде замінювати існуюче 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 і було вилучене з проекту до стандартизації.
Говард Хенант


7

Було багато дискусій щодо неявного руху, що порушує сумісність

( старша сторінка з відповідною дискусією )

Якщо ви читаєте в коментарях, неявна повернення ходу також є суттєвою зміною.


Результатом цих обговорень є те, що її практично усунули майже у всіх випадках. Чи є проблеми з тим, що залишилося?
Dennis Zickefoose

@Dennis: Так. Ваше запитання вже було задано, відповіли і обговорювались до смерті на цій сторінці спостереження
Ben Voigt

Ах, на мобільній сторінці коментарі не з’являлися. Так чи інакше, це набагато корисніше посилання ... Історичні дивацтва процесу стандартизації не такі актуальні (якщо ви не використовуєте MSVC, який, на мою думку, використовує цей перший проект).
Dennis Zickefoose

@Dennis: Я думаю, ти маєш рацію. У своїй відповіді я перемістив посилання навколо деяких.
Ben Voigt

На жаль, 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і без імені.
Ben Voigt

Я сподівався когось вилавити. Я тільки бажаю, щоб @Xeo не так швидко видалив його коментар, тому що я не зміг його прочитати!
Гонки легкості по орбіті

@Xeo: Не перекопуючи граматику, я впевнений, що авто просто не є правильним ключовим словом. Якби це було, воно, ймовірно, спрацювало б, як ви очікували, але це, мабуть, справді важко визначити правильно.
Денніс Зіккефуз

Скажімо, ви мене зловили. Він буквально ігнорував структуру. :)
Xeo

@Tomalek: Xeo правильно вказав, що C ++ 03 не має неявного int.
Ben Voigt

-4

Мовні особливості

  1. Уніфікована і загальна ініціалізація за допомогою {}
  2. авто
  3. Попередження звуження
  4. constexpr
  5. Діапазон на основі циклу
  6. nullptr
  7. перерахунок класу
  8. static_assert
  9. std :: inicijalizer_list
  10. Оцінки посилань (семантика переміщення)
  11. >>
  12. Лямбда
  13. Варіанти шаблонів
  14. Псевдоніми типу та шаблону
  15. Символи Unicode
  16. довгий довгий цілий тип
  17. алігнас і алігноф
  18. decltype
  19. Сирі літеральні рядки
  20. Узагальнений ПОД
  21. Узагальнені союзи
  22. Локальні класи як аргументи шаблону
  23. Синтаксис повернення суфікса
  24. [[несе_залежність]] і [[неретурн]]
  25. noexcept специфікатор
  26. noexcept оператора.
  27. Особливості C99:
    • розширені інтегральні типи
    • конкатенація вузької / широкої струни
    • _ _ STDC_HOSTED _ _
    • _Прагма (X)
    • vararg макроси та порожні макроаргументи
  28. _ _ func _ _
  29. Вбудовані простори імен
  30. Делегуючі конструктори
  31. Ініціалізатори учасників класу
  32. за замовчуванням та видалити
  33. Явні оператори перетворення
  34. Визначені користувачем літерали
  35. Зовнішні шаблони
  36. Аргументи шаблону за замовчуванням для шаблонів функцій
  37. Наслідування конструкторів
  38. переосмислення та остаточне
  39. Простіше і більш загальне правило SFINAE
  40. Модель пам'яті
  41. нитка_локальна

Компоненти стандартної бібліотеки

  1. inicijalizer_list для контейнерів
  2. Перемістіть семантику для контейнерів
  3. вперед_ список
  4. Хеш-контейнери
    • unordered_map
    • unordered_multimap
    • unorряд_set
    • unordered_multiset
  5. Показники управління ресурсами
    • unique_ptr
    • shared_ptr
    • слабкий_птр
  6. Підтримка одночасності
    • нитка
    • мутекси
    • замки
    • змінні умови
  7. Підтримка одночасності вищого рівня
    • Packaged_thread
    • майбутнє
    • обіцянка
    • асинхронізація
  8. кортежі
  9. регекс
  10. Випадкові числа
    • рівномірний_розподіл
    • нормальний_розподіл
    • 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 специфікація винятків
    • Uncepted_handler
    • set_unexpected
    • get_unexpected
    • несподіваний
  4. Об'єкти функцій та пов'язані з ними функції
  5. auto_ptr
  6. реєструвати
  7. ++ на bool
  8. експорт
  9. Касти в стилі C

3
Це не дає відповіді на запитання.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.