Какие изменения, внесенные в С++ 14, могут потенциально нарушить программу, написанную на С++ 11?

Введение

В стандарте С++ 14 (aka. С++ 1y) в состоянии, близком к окончательному, программисты должны задать себе обратную совместимость и проблемы, связанные с такими.


Вопрос

В ответах этот вопрос указано, что в Стандарте есть Приложение, посвященное информации об изменениях между версиями.

Было бы полезно, если бы эти потенциальные проблемы в вышеупомянутом Приложении могли быть объяснены, возможно, с помощью любых официальных документов, связанных с тем, что упоминается там.

  • В соответствии со стандартом: какие изменения, внесенные в С++ 14, могут потенциально нарушить программу, написанную на С++ 11?

Ответ 1

Примечание. В этом сообщении я считаю, что "изменение прерывания" должно быть либо, либо и тем, и другого:
1. изменение, которое сделает законным С++ 11 плохо сформированным при компиляции С++ 14 и;
  2. изменение, которое изменит поведение во время выполнения при компиляции С++ 14, vs С++ 11.


С++ 11 vs С++ 14, что говорит стандарт?

Стандартная черновик (n3797) имеет раздел, посвященный только такой информации, где он описывает (потенциально нарушающие) различия между одной версией стандарта и другой.

Это сообщение использовало этот раздел [diff.cpp11] в качестве основы для полуразработанного обсуждения изменений, которые могут повлиять на код, написанный для С++ 11, но скомпилированный как С++ 14.


C.3.1] Цифровые разделители

Разделитель цифр был введен таким образом, чтобы можно было более читаемым образом писать числовые литералы и разделить их таким образом, что это более естественный способ.

int x = 10000000;   // (1)
int y = 10'000'000; // (2), C++14

Легко видеть, что (2) намного легче читать, чем (1) в приведенном выше фрагменте, в то время как оба инициализатора имеют одинаковое значение.

Потенциальная проблема в этой функции заключается в том, что одинарная кавычка всегда обозначала начало/конец символьного литерала в С++ 11, но в С++ 14 одиночная кавычка может либо окружать буквенный символ, или используется ранее показанным образом (2).


Пример фрагмента, легальный как на С++ 11, так и на С++ 14, но с другим поведением.

#define M(x, ...) __VA_ARGS__

int a[] = { M(1'2, 3'4, 5) };

// int a[] = { 5 };        <-- C++11
// int a[] = { 3'4, 5 };   <-- C++14
//                              ^-- semantically equivalent to `{ 34, 5 }`

(Примечание. Более подробную информацию о одиночных кавычках в качестве разделителей цифр можно найти в n3781.pdf)


C.3.2] Размер освобождения

С++ 14 предоставляет возможность объявить глобальную перегрузку operator delete, подходящую для размера освобождения, что было невозможно в С++ 11.

Однако стандарт также предусматривает, что разработчик не может объявить только одну из двух связанных функций ниже, он должен объявить либо none, либо как; который указан в [new.delete.single] p11.

void operator delete (void*) noexcept;
void operator delete (void*, std::size_t) noexcept; // sized deallocation


Дополнительная информация о потенциальной проблеме:

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

     

Примечание: Цитата взята из n3536 - Расширенное освобождение С++

(Примечание. Больше интереса имеется в документе под названием n3536 - С++ Sized Deallocation, написанном Лоуренсом Кроулом)


C.3.3] constexpr функции-члены, уже неявно const

Есть много изменений в constexpr в С++ 14, но единственное изменение, которое изменит семантику между С++ 11 и С++ 14, - это постоянство функции-члена, помеченной как constexpr.

Обоснование этого изменения заключается в том, чтобы позволить членам-членам constexpr мутировать объект, к которому они принадлежат, что-то, что разрешено из-за релаксации constexpr.

struct A { constexpr int func (); };

// struct A { constexpr int func () const; }; <-- C++11
// struct A { constexpr int func ();       }; <-- C++14


Рекомендуемый материал об этом изменении, и почему это достаточно важно, чтобы ввести потенциальный поломка кода:


Пример фрагмента, законный как в С++ 11, так и в С++ 14, но с другим поведением

struct Obj {
  constexpr int func (int) {
    return 1;
  }

  constexpr int func (float) const {
    return 2;
  }
};

Obj const a = {}; 
int const x = a.func (123);

// int const x = 1;   <-- C++11
// int const x = 2;   <-- C++14

C.3.4] Удаление std::gets

std::gets был удален из стандарта Библиотека, потому что считается опасной.

Последствия этого - это, конечно, попытка скомпилировать код, написанный для С++ 11, в С++ 14, где такая функция используется, скорее всего, просто не скомпилируется.


(Примечание: существуют способы записи code, которые не поддаются компиляции и имеют другое поведение, которое зависит от удаление std::gets из стандартной библиотеки)