Журнал изменений Microsoft C/C++ в версиях с 2003 по 2015

В этой статье описываются критические изменения, начиная с Visual Studio 2015 и до Visual Studio 2003, а термины "новое поведение" и "теперь" относятся к Visual Studio 2015 и более поздним версиям. Термины "старое поведение" и "раньше" относятся к Visual Studio 2013 и более ранних версий.

Сведения о последней версии Visual Studio см. в статье "Новые возможности для C++ в Visual Studio и C++ по улучшению соответствия в Visual Studio.

Примечание.

Принципы работы с двоичными файлами в Visual Studio 2017 по сравнению с Visual Studio 2015 существенно не изменились.

При обновлении до новой версии Visual Studio могут возникать ошибки компиляции и ошибки во время выполнения кода, который ранее правильно компилировался и выполнялся. Изменения в новой версии, вызывающие такие проблемы, именуются критическими изменениямии, как правило, связаны с изменениями стандарта языка C++, сигнатур функций или структуры объектов в памяти.

Чтобы избежать ошибок во время выполнения, которые сложно выявить и диагностировать, рекомендуется не создавать статических ссылок на двоичные файлы, скомпилированные с помощью другой версии компилятора. Кроме того, при обновлении проекта EXE или DLL обязательно обновите библиотеки, на которые он ссылается. Не передавайте типы CRT (среда выполнения языка C) или стандартной библиотеки C++ между двоичными файлами (в том числе библиотеками DLL), скомпилированными с помощью разных версий компилятора. Дополнительные сведения см. в разделе Potential Errors Passing CRT Objects Across DLL Boundaries.

Не создавайте код, зависящий от конкретной структуры, для объекта, который не является интерфейсом COM или объектом POD. Если вы написали подобный код, после обновления обязательно убедитесь в его работоспособности. Дополнительные сведения см. в статье Переносимость на границах API.

Кроме того, постоянные улучшения соответствия компилятора иногда могут изменить то, как компилятор распознает существующий исходный код. Например, во время сборки могут возникнуть новые или другие ошибки или даже поведенческие различия в коде, который был собран ранее и, казалось, работал правильно. Несмотря на то, что эти улучшения не являются критическими изменениями, подобно описываемым в данном документе, для устранения этих проблем может потребоваться внести изменения в исходный код:

Изменения соответствия Visual Studio 2015

Библиотека времени выполнения C (CRT)

Общие изменения

  • Двоичные файлы, полученные в результате рефакторинга

    Был осуществлен рефакторинг библиотеки CRT, в результате чего она разделена на два разных двоичных файла: универсальную библиотеку CRT (ucrtbase), которая содержит большинство стандартных функциональных возможностей, и библиотеку времени выполнения VC (vcruntime). Библиотека vcruntime содержит функции, связанные с компилятором, такие как обработка исключений и встроенные функции. Если вы используете параметры проекта по умолчанию, это изменение не влияет на вас, так как компоновщик использует новые библиотеки по умолчанию автоматически. Если вы установили для свойства Игнорировать все стандартные библиотекикомпоновщика в проекте значение Да или используете параметр компоновщика /NODEFAULTLIB в командной строке, необходимо обновить список библиотек (в свойстве Дополнительные зависимости), чтобы включить в него новые подвергнутые рефакторингу библиотеки. Замените старую библиотеку CRT (libcmt.lib, libcmtd.lib, msvcrt.lib) msvcrtd.libэквивалентными рефакторинговыми библиотеками. Для каждой из двух подвергнутых рефакторингу библиотек существует статическая (.lib) и динамическая (.dll) версии, а также версия выпуска (без суффикса) и отладочная версия (с суффиксом "d"). Динамические версии имеют библиотеку импорта, с которой выполняется связь. Две рефакторинговые библиотеки — универсальная библиотека CRT, в частности ucrtbase.dll или ucrtbase.lib, ucrtbased.dll или ucrtbased.lib, а также библиотека среды выполнения VC, libvcruntime.libvcruntimeversion.dll и libvcruntimed.libvcruntimedversion.dll. Версия в Visual Studio 2015 и Visual Studio 2017 — 140. См. раздел CRT Library Features.

<locale.h>

  • localeconv

    Функция, объявленная localeconv в locale.h, теперь работает правильно при включении языкового стандарта для каждого потока. В предыдущих версиях библиотеки эта функция возвращала бы данные lconv для глобального языкового стандарта, а не для языкового стандарта потока.

    При использовании языковых стандартов отдельных потоков следует проверить использование localeconv. Если в коде предполагается, что данные lconv возвращаются для глобального языкового стандарта, следует внести исправления.

<math.h>

  • Перегрузки C++ для функций математической библиотеки

    В предыдущих версиях определены некоторые, но не все перегрузки <math.h> C++ для функций математической библиотеки. Остальные перегрузки находились в заголовке <cmath> . Код, который включен <math.h> , может иметь проблемы с разрешением перегрузки функций. Теперь перегрузки C++ были удалены и <math.h> найдены только в <cmath>.

    Чтобы устранить ошибки, включите <cmath> получение объявлений функций, из которых были удалены <math.h>. Перемещенные функции:

    • double abs(double) и float abs(float).
    • double pow(double, int), , float pow(float, float)float pow(float, int), long double pow(long double, long double)long double pow(long double, int)
    • Версии float и long double функций с плавающей запятой acos, acosh, asin, asinh, atan, atanh, atan2, cbrt, ceil, copysign, cos, cosh, erf, erfc, exp, exp2, expm1, fabs, fdim, floor, fma, fmax, fmin, fmod, frexp, hypot, ilogb, ldexp, lgamma, llrint, llround, log, log10, log1p, log2, lrint, lround, modf, nearbyint, nextafter, nexttoward, remainder, remquo, rint, round, scalbln, scalbn, sin, sinh, sqrt, tan, tanh, tgamma и trunc

    Если у вас есть код, который используется abs с типом с плавающей запятой, который включает <math.h> только заголовок, версии с плавающей запятой больше не будут доступны. Вызов, даже имеющий аргумент с плавающей запятой, теперь разрешается в abs(int), что приводит к ошибке:

    warning C4244: 'argument' : conversion from 'float' to 'int', possible loss of data
    

    Исправление этого предупреждения заключается в замене вызова abs на версию с плавающей запятой, например fabs для двойного аргумента absили fabsf для аргумента с плавающей запятой, или включить <cmath> заголовок и продолжить использоватьabs.

  • Соответствие требованиям к плавающей запятой

    В математическую библиотеку внесено множество изменений для повышения уровня соответствия спецификациям стандарта IEEE-754 и дополнения F стандарта C11 относительно специальных вариантов входных данных, например значений NaN и бесконечностей. Например, входные данные несигнальных NaN, которые часто обрабатывались как ошибки в предыдущих версиях библиотеки, больше не считаются ошибками. См. стандарт IEEE 754 и приложение F к стандарту C11.

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

  • FLT_ROUNDS

    В Visual Studio 2013 макрос FLT_ROUNDS расширен до константного выражения, которое было неверным, поскольку режим округления настраивается во время выполнения, например путем вызова fesetround. Теперь макрос FLT_ROUNDS является динамическим и правильно отражает текущий режим округления.

<new> и <new.h>

  • new и delete

    В предыдущих версиях библиотеки функции new и delete определяемого реализацией оператора были экспортированы из библиотеки DLL библиотеки времени выполнения (например, msvcr120.dll). Эти функции оператора теперь всегда статически привязаны к двоичным файлам, даже если используются DLL библиотеки времени выполнения.

    Это не является критическим изменением для машинного или смешанного кода (/clr). Однако для кода, компилируемого как /clr:pure, это изменение может привести к ошибке компиляции кода. При компиляции кода как /clr:pure может потребоваться добавить #include <new> или #include <new.h> для устранения ошибок сборки, вызванных этим изменением. Параметр /clr:pure отмечен как нерекомендуемый для использования в Visual Studio 2015 и не поддерживается в Visual Studio 2017. Код, который должен быть "чистым", необходимо портировать на C#.

<process.h>

  • _beginthread и _beginthreadex.

    _beginthreadex Теперь _beginthread функции содержат ссылку на модуль, в котором процедура потока определена в течение длительности потока. Это помогает гарантировать, что модули не будут выгружены до завершения потока.

<stdarg.h>

  • va_start и ссылочные типы

    При компиляции кода C++ теперь проверяется во время компиляции, va_start что аргумент, переданный в него, не является ссылочным типом. Аргументы ссылочных типов запрещены стандартом C++.

<stdio.h> и <conio.h>.

  • Теперь семейство функций printf и scanf определяется встроенным образом.

    Определения всех printfscanf функций были перемещены в встроенные <stdio.h><conio.h>и другие заголовки CRT. Это критическое изменение приводит к ошибке компоновщика (LNK2019, неразрешенный внешний символ) для всех программ, где эти функции объявляются локально, однако отсутствуют соответствующие заголовки CRT. Если это возможно, необходимо обновить код, чтобы включить заголовки CRT (т. е. добавить #include <stdio.h>) и встроенные функции, но если вы не хотите изменять код, чтобы включить эти файлы заголовков, альтернативным решением является добавление legacy_stdio_definitions.lib в входные данные компоновщика.

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

    Если проект связан со статическими библиотеками, которые были скомпилированы в выпуске Visual Studio, предшествующем 2015, компоновщик может сообщить о неразрешенном внешнем символе. Эти ошибки могут ссылаться на внутренние определения для _iob, _iob_funcили связанные импорты для определенных <stdio.h> функций в виде imp*. Корпорация Майкрософт рекомендует перекомпилировать все статические библиотеки с использованием последней версии компилятора и библиотек C++ при обновлении проекта. Если библиотека создана сторонним разработчиком и ее исходный код недоступен, следует запросить обновленный двоичный файл у стороннего разработчика или инкапсулировать использование этой библиотеки в отдельную библиотеку DLL, компилируемую с использованием старой версии компилятора и библиотек.

    Предупреждение

    При связывании с Windows SDK 8.1 или более ранней версии могут возникнуть следующие ошибки неразрешенного внешнего символа. В этом случае следует устранить ошибку, добавив legacy_stdio_definitions.lib во входные данные компоновщика, как описано выше.

    Чтобы устранить неразрешенные ошибки символов, можно попытаться dumpbin.exe проверить символы, определенные в двоичном файле. Попробуйте выполнить следующую команду для просмотра символов, определенных в библиотеке.

    dumpbin.exe /LINKERMEMBER somelibrary.lib
    
  • gets и _getws

    Функции gets и _getws были удалены. Функция gets была удалена из стандартной библиотеки C в C11, так как ее нельзя использовать безопасным образом. Функция _getws была эквивалентным функции gets расширением Майкрософт, предназначенным для двухбайтовых строк. В качестве альтернативы этим функциям можно использовать fgets, fgetws, gets_s и _getws_s.

  • _cgets и _cgetws

    Функции _cgets и _cgetws были удалены. В качестве альтернативы этим функциям можно использовать _cgets_s и _cgetws_s.

  • Форматирование бесконечностей и значений NaN

    В предыдущих версиях бесконечности и значения NaN форматировались с использованием набора строк sentinel из MSVC.

    • Бесконечность: 1.#INF

    • Несигнальное значение NaN: 1. #QNAN

    • Сигнальное значение NaN: 1.#SNAN

    • Неопределенное значение NaN: 1.#IND

    Любой из этих форматов мог иметь префикс в виде знака и мог немного отличаться в зависимости от ширины поля и точности (иногда с необычными эффектами, например printf("%.2f\n", INFINITY) приводило к выводу 1.#J, так как #INF "округлялось" до точности в два разряда). В C99 появились новые требования к форматированию бесконечностей и значений NaN. Реализация MSVC теперь соответствует этим требованиям. Далее приведены новые строки:

    • Бесконечность: inf

    • Несигнальное значение NaN: nan

    • Сигнальное значение NaN: nan(snan)

    • Неопределенное значение NaN: nan(ind)

    Любая из них может иметь префикс в виде знака. Если используется описатель формата прописных букв (%F вместо %f), строки выводятся прописными буквами (INF вместо inf), как это и требуется.

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

  • Форматирование и анализ при наличии плавающей запятой

    В целях обеспечения правильности работы были введены новые алгоритмы форматирования и синтаксического анализа при наличии плавающей запятой. Это изменение влияет на семейства функций printf и scanf, а также функции, такие как strtod.

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

    printf("%.0f\n", pow(2.0, 80))
    

    Старые выходные данные:

    1208925819614629200000000
    

    Новые выходные данные:

    1208925819614629174706176
    

    Старые алгоритмы анализа используют не более 17 значащих цифр из строки ввода, а остальные цифры не учитывают. Этого достаточно для создания хорошего приближения для значения, представленного строкой, и результат обычно очень близок к правильно округленному результату. Новая реализация учитывает все имеющиеся цифры и выдает правильно округленный результат для всех входных данных (длиной до 768 цифр). Кроме того, эти функции теперь учитывают режим округления (управляемый или fesetround). Это критическое изменение поведения, так как эти функции могут выдавать различные результаты. Новые результаты всегда являются более правильными по сравнению со старыми.

  • Анализ шестнадцатеричных значений и значений бесконечности/NaN с плавающей запятой

    Алгоритмы анализа выражений с плавающей запятой теперь будут анализировать шестнадцатеричные строки с плавающей запятой (например, созданные описателями %a и %A формата printf) и все строки бесконечностей и NaN, созданные функциями printf, как описано выше.

  • Заполнение нулями в %A и %a

    Описатели формата %a и %A форматируют значение с плавающей запятой как шестнадцатеричную мантиссу и двоичный показатель степени. В предыдущих версиях функции printf заполняли строки нулями неправильно. Например, printf("%07.0a\n", 1.0) выводила 00x1p+0, хотя должна вывести 0x01p+0. Эта ошибка была исправлена.

  • Точность %A и %a

    В предыдущих версиях библиотеки точность описателей формата %A и %a по умолчанию была равна 6. Теперь точность по умолчанию составляет 13 для обеспечения соответствия стандарту.

    Это изменяет поведение во время выполнения в выходных данных любой функции, которая использует строку формата с %A или %a. При старом поведении описатель %A мог давать выходные данные "1.1A2B3Cp+111". Теперь для того же значения выводится "1.1A2B3C4D5E6F7p+111". Чтобы получить старое поведение, можно указать точность, например %.6A. См. раздел Precision Specification (Спецификация точности).

  • Описатель %F

    Теперь поддерживается описатель формата/преобразования %F. Функционально он эквивалентен описателю формата %f, за исключением того, что бесконечности и значения NaN форматируются с помощью прописных букв.

    В предыдущих версиях данная реализация использовалась для анализа F и N в качестве модификаторов длины. Это поведение относится ко временам сегментированных адресных пространств: эти модификаторы длины использовались для обозначения дальнего и ближнего указателей соответственно как %Fp или %Ns. Такое поведение было удалено. Теперь при обнаружении %F он рассматривается как описатель формата %F, а %N при обнаружении теперь рассматривается как недопустимый параметр.

  • Форматирование показателя степени

    Описатели формата %e и %E форматируют значение с плавающей запятой как десятичную мантиссу и показатель степени. В некоторых случаях описатели формата %G и %g также форматируют числа в этой форме. В предыдущих версиях CRT всегда создает строки с показателями степени из трех цифр. Например, printf("%e\n", 1.0) выдает 1.000000e+000, что неправильно. C требует того, что если показатель степени можно представить с помощью одной или двух цифр, то следует вывести только две цифры.

    В Visual Studio 2005 был добавлен переключатель глобальной согласованности: _set_output_format. Программа может вызвать эту функцию с аргументом _TWO_DIGIT_EXPONENT, чтобы обеспечить согласованный вывод показателя степени. Поведение по умолчанию было изменено на соответствующий стандартам режим вывода показателя степени.

  • Проверка строки формата

    В предыдущих версиях функции printf и scanf без уведомления принимали многие недопустимые строки формата, иногда с необычными эффектами. Например, % hlhlhld расценивалась как %d. Теперь все недопустимые строки формата считаются недопустимыми параметрами.

  • Проверка строки режима fopen

    В предыдущих версиях семейство функций fopen без уведомления принимало некоторые недопустимые строки режима, например r+b+. Недопустимые строки режима теперь обнаруживаются и обрабатываются как недопустимые параметры.

  • Режим _O_U8TEXT

    Функция _setmode теперь правильно сообщает режим для потоков, открытых в режиме _O_U8TEXT. В предыдущих версиях библиотеки такие потоки считались открытыми в режиме _O_WTEXT.

    Это критическое изменение, если код определяет режим _O_WTEXT для потоков, имеющих кодировку UTF-8. Если приложение не поддерживает UTF_8, рекомендуется добавить поддержку этой широко распространенной кодировки.

  • snprintf и vsnprintf

    Теперь реализованы функции snprintf и vsnprintf. Устаревший код часто предоставлял определения версий макроса этих функций, так как они не были реализованы библиотекой CRT, но в более поздних версиях они не нужны. Если snprintf или vsnprintf определен как макрос перед включением<stdio.h>, компиляция теперь завершается ошибкой, указывающей, где был определен макрос.

    Как правило, для исправления этой проблемы следует удалить все объявления snprintf или vsnprintf в пользовательском коде.

  • Функция tmpnam создает удобные имена файлов

    В предыдущих версиях функции tmpnam и tmpnam_s создавали имена файлов в корневом каталоге диска (например, \sd3c.). Теперь эти функции создают пути имен файлов во временном каталоге.

  • Инкапсуляция FILE

    В предыдущих версиях полный тип FILE был определен общедоступным <stdio.h>образом, поэтому пользовательский код можно было связаться с ФАЙЛом и изменить его внутренние элементы. Библиотека была изменена, чтобы скрыть детали реализации. В рамках этого изменения ФАЙЛ, как определено в <stdio.h> настоящее время является непрозрачным типом, и его члены недоступны вне самой CRT.

  • _outp и _inp

    Функции _outp, _outpw, _outpd, _inp, _inpw и _inpd были удалены.

<stdlib.h>, <malloc.h> и <sys/stat.h>

  • strtof и wcstof

    Функциям strtof и wcstof не удавалось задать для errno значение ERANGE, если значение нельзя было представить как значение с плавающей запятой. Данная ошибка касалась двух этих функций и не затрагивала функции strtod, wcstod, strtold и wcstold. Эта проблема была устранена посредством критического изменения среды выполнения.

  • Выровненные функции выделения

    В предыдущих версиях выровненные функции выделения (_aligned_malloc, _aligned_offset_malloc и т. п.) без уведомления принимали запросы для блока с выравниванием 0. Требуемое выравнивание должно быть степенью двойки, чем ноль не является. Теперь запрошенное выравнивание 0 рассматривается как недопустимый параметр. Эта проблема была устранена посредством критического изменения среды выполнения.

  • Функции кучи

    Функции _heapadd, _heapset и _heapused были удалены. Эти функции стали неработоспособными после обновления CRT для использования кучи Windows.

  • smallheap

    Параметр включения режимов smallheap был удален. См. раздел Link Options.

  • _stat

    Семейство _stat функций, используемых CreateFile в Visual Studio 2015, а не FindFirstFile в Visual Studio 2013 и более ранних версиях. Это означает, что на пути, заканчивающегося косой чертой, успешно выполняется, _stat если путь относится к каталогу, а не раньше, когда функция будет ошибкой с errno заданным значением ENOENT.

<string.h>

  • wcstok

    Сигнатура функции wcstok была изменена для соответствия стандарту C. В предыдущих версиях библиотеки эта функция имела сигнатуру:

    wchar_t* wcstok(wchar_t*, wchar_t const*)
    

    Она использовала контекст потока для отслеживания состояния в рамках вызовов, как и для strtok. Теперь функция имеет сигнатуру wchar_t* wcstok(wchar_t*, wchar_t const*, wchar_t**) и требует, чтобы вызывающий объект передал контекст в качестве третьего аргумента функции.

    Была добавлена новая функция _wcstok со старой сигнатурой для упрощения переноса. При компиляции кода C++ присутствует также внутренняя перегрузка wcstok, имеющая старую сигнатуру. Эта перегрузка была признана нерекомендуемой. В коде C можно определить _CRT_NON_CONFORMING_WCSTOK, чтобы использовать _wcstok вместо wcstok.

<time.h>

  • clock

    В предыдущих версиях clock функция была реализована с помощью API GetSystemTimeAsFileTimeWindows. При такой реализации функция clock зависела от системного времени и поэтому не была обязательно монотонной. Функция часов была повторно завершена с точки зрения QueryPerformanceCounter и теперь монотонна.

  • fstat и _utime

    В предыдущих версиях функции _statfstatи _utime функции обрабатывают летнее время неправильно. До Visual Studio 2013 все эти функции неправильно корректировали зимнее время, как если бы применялось летнее время.

    В Visual Studio 2013 проблема устранена в _stat семействе функций, но аналогичные проблемы в fstat функциях и _utime семействах функций не были исправлены. Это частичное исправление привело к проблемам, вызванным несогласованностью функций. Теперь fstat были исправлены и _utime семейства функций, поэтому все эти функции теперь обрабатывают летнее время правильно и согласованно.

  • asctime

    В предыдущих версиях asctime функция будет заполнять однозначные дни с начальным нулем, например: Fri Jun 06 08:00:00 2014 Спецификация требует, чтобы такие дни дополнялись начальным пробелом, как в Fri Jun 6 08:00:00 2014. Теперь эта проблема устранена.

  • strftime и wcsftime

    Функции strftime и wcsftime теперь поддерживают описатели формата %C, %D, %e, %F, %g, %G, %h, %n, %r, %R, %t, %T, %u и %V. Кроме того, модификаторы E и O, анализируются, но игнорируются.

    Описатель формата %c указывается как обеспечивающий "соответствующее представление даты и времени" для текущего языкового стандарта. В языковом стандарте C это представление должно быть таким же, как и %a %b %e %T %Y. Это та же форма, которую выдает asctime. В предыдущих версиях описатель формата %c неправильно форматировал время с помощью представления MM/DD/YY HH:MM:SS. Теперь эта проблема устранена.

  • timespec и TIME_UTC

    Теперь заголовок <time.h> определяет timespec тип и timespec_get функцию из стандарта C11. Кроме того, теперь определен макрос TIME_UTC, предназначенный для использования с функцией timespec_get. Это критическое изменение для кода, имеющего конфликтующее определение для любого из этих идентификаторов.

  • CLOCKS_PER_SEC

    Макрос CLOCKS_PER_SEC теперь расширяется до целого числа типа clock_t, как требует стандарт языка C.

стандартная библиотека C++

Для активации новых способов оптимизации и проверки результатов отладки стандартная библиотека C++, реализованная в Visual Studio, намеренно ограничивает совместимость двоичных данных из одной версии в следующей версии. Поэтому при использовании стандартной библиотеки C++ файлы объектов и статические библиотеки, скомпилированные с помощью разных версий, нельзя одновременно добавить в один двоичный файл (EXE или DLL), а объекты стандартной библиотеки C++ нельзя передать из одного двоичного файла в другой, если эти файлы скомпилированы при помощи разных версий. В этом случае возникает ошибка компоновщика, связанная с несоответствиями _MSC_VER. (_MSC_VER — это макрос, содержащий основную версию компилятора, например 1800 для Visual Studio 2013.) Эта проверка не может обнаруживать сочетание библиотек DLL и не может обнаруживать микширование, включающее Visual Studio 2008 или более ранних версий.

  • Файлы include стандартной библиотеки C++

    В структуру включения в заголовках стандартной библиотеки C++ были внесены некоторые изменения. Заголовки стандартной библиотеки C++ могут включать друг друга неопределенными способами. В общем случае следует писать код таким образом, чтобы он наверняка включал все заголовки, которые требуются в соответствии со стандартом C++, и не зависел от того, какие заголовки стандартной библиотеки C++ включают другие заголовки стандартной библиотеки C++. Позволяет переносить код между версиями и платформами. Как минимум два изменения в файлах заголовков Visual Studio 2015 могут затронуть пользовательский код. Во-первых, <string> больше не включает <iterator>. Во-вторых, <tuple> теперь объявляется std::array без включения всех <array>элементов, которые могут прерывать код с помощью следующей комбинации конструкций кода: код имеет переменную с именем array, и у вас есть директива using "using namespace std;", и вы включаете заголовок стандартной библиотеки C++ (например <functional>, который включает в себя <tuple>, который теперь объявляет std::array.

  • steady_clock

    steady_clock Реализация <chrono> изменилась в соответствии со стандартными требованиями C++ для устойчивости и монотонности. steady_clock теперь основан QueryPerformanceCounter на и high_resolution_clock теперь является типдифактом для steady_clock. В результате в Visual Studio steady_clock::time_point теперь является определением типа для chrono::time_point<steady_clock>, однако в других реализациях это может быть не так.

  • Распределители и константы

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

    bool operator==(const MyAlloc& other)
    

    необходимо обновить их, объявив членами-константами.

    bool operator==(const MyAlloc& other) const
    
  • Элементы-константы

    Стандарт C++ всегда запрещает контейнеры элементов const (например vector<const T> , или set<const T>). Система Visual Studio 2013 и более ранних версий принимала такие контейнеры. В текущей версии при компиляции таких контейнеров выдается ошибка.

  • std::allocator::deallocate

    В Visual Studio 2013 и более ранних версиях std::allocator::deallocate(p, n) игнорировал аргумент, переданный для n. Стандарт C++ всегда должен быть равен значению, передаваемому в качестве первого аргумента вызову allocate, возвращаемому p. Однако в текущей версии значение n проверяется. Код, который передает для n аргументы, отличающиеся от требований стандарта, может завершиться со сбоем во время выполнения.

  • hash_map и hash_set

    Файлы заголовков <hash_map> , не стандартные и нерекомендуемые в Visual Studio 2015, <hash_set> будут удалены в будущем выпуске. Взамен используйте <unordered_map> и <unordered_set>.

  • Средства сравнения и operator()

    Ассоциативные контейнеры ( <map> семейство) теперь требуют, чтобы их компраторы имели вызываемые операторы вызовов функций. Компиляция следующего кода в объявлении класса средства сравнения теперь завершается со сбоем:

    bool operator()(const X& a, const X& b)
    

    Чтобы устранить эту ошибку, измените объявление функции на:

    bool operator()(const X& a, const X& b) const
    
  • Признаки типов

    Старые имена для признаков типов из более ранней версии проекта стандарта C++ были удалены. В C++11 они были изменены, и обновление до значений C++11 было сделано в Visual Studio 2015. В следующей таблице показаны старые и новые имена.

    Старое имя Новое имя
    add_reference add_lvalue_reference
    has_default_constructor is_default_constructible
    has_copy_constructor is_copy_constructible
    has_move_constructor is_move_constructible
    has_nothrow_constructor is_nothrow_default_constructible
    has_nothrow_default_constructor is_nothrow_default_constructible
    has_nothrow_copy is_nothrow_copy_constructible
    has_nothrow_copy_constructor is_nothrow_copy_constructible
    has_nothrow_move_constructor is_nothrow_move_constructible
    has_nothrow_assign is_nothrow_copy_assignable
    has_nothrow_copy_assign is_nothrow_copy_assignable
    has_nothrow_move_assign is_nothrow_move_assignable
    has_trivial_constructor is_trivially_default_constructible
    has_trivial_default_constructor is_trivially_default_constructible
    has_trivial_copy is_trivially_copy_constructible
    has_trivial_move_constructor is_trivially_move_constructible
    has_trivial_assign is_trivially_copy_assignable
    has_trivial_move_assign is_trivially_move_assignable
    has_trivial_destructor is_trivially_destructible
  • Политики launch::any и launch::sync

    Нестандартные политики launch::any и launch::sync были удалены. Вместо этого для launch::any используйте launch:async | launch:deferred. Для launch::sync используйте launch::deferred. См. раздел launch Enumeration (Перечисление launch).

MFC и ATL

  • Microsoft Foundation Classes (MFC)

    больше не входит в состав обычной установки Visual Studio из-за большого размера. Чтобы установить MFC, выберите параметр выборочной установки в программе установки Visual Studio 2015. При наличии Visual Studio 2015 можно установить MFC, повторно запустив программу установки Visual Studio. Выберите выборочную установку, а затем Microsoft Foundation Classes. Программу установки Visual Studio можно запустить из раздела Программы и компонентыпанели управления или с установочного носителя.

    Распространяемый пакет Visual C++ по-прежнему содержит эту библиотеку.

Среда выполнения с параллелизмом

  • Макрос Yield из Windows.h конфликтует с concurrency::Context::Yield

    Ранее среда выполнения с параллелизмом использовала #undef, чтобы отменить определение макроса Yield во избежание конфликтов между макросом Yield, определенным в Windows.h, и функцией concurrency::Context::Yield. Этот #undef был удален, и был добавлен новый эквивалентный вызов функции API-интерфейса concurrency::Context::YieldExecution, не вызывающий конфликтов. Для устранения конфликтов с Yield можно обновить код для вызова функции YieldExecution или заключить имя функции Yield в скобки в местах вызова, как показано в следующем примере:

    (concurrency::Context::Yield)();
    

Улучшения соответствия компилятора в Visual Studio 2015

При обновлении кода из предыдущих версий также могут возникнуть ошибки компилятора, связанные с улучшениями соответствия в Visual Studio 2015. Эти усовершенствования не нарушают совместимость двоичных данных из предыдущих версий Visual Studio, но они могут приводить к ошибкам компилятора там, где они не были устранены ранее. Дополнительные сведения см. в статье Visual C++ What's New 2003 through 2015 (Новые возможности Visual C++ 2003–2015).

В Visual Studio 2015 постоянные улучшения соответствия компилятора иногда могут изменить то, как компилятор распознает существующий исходный код. В результате во время сборки могут возникнуть новые или другие ошибки или даже поведенческие различия в коде, который был собран ранее и, казалось, работал правильно.

К счастью, эти различия имеют минимальное влияние или совсем не затрагивают большую часть исходного кода. Если требуется внести изменения в исходный код, чтобы устранить эти различия, как правило, применяются незначительные исправления. Мы включили много примеров ранее допустимого исходного кода, который может потребоваться изменить (раньше), и исправлений (теперь).

Несмотря на то, что эти различия могут повлиять на исходный код и другие артефакты сборки, они не влияют на совместимость двоичных файлов между обновлениями версий Visual Studio. Критическое изменение — это более серьезное изменение, которое может повлиять на совместимость двоичных файлов, но нарушения совместимости происходят только между основными версиями Visual Studio, например между Visual Studio 2013 и Visual Studio 2015. Сведения о критических изменениях, введенных со времени выпуска Visual Studio 2013 до выпуска Visual Studio 2015, см. в статье Visual Studio 2015 Conformance Changes (Улучшения соответствия в Visual Studio 2015).

Улучшения соответствия в Visual Studio 2015

  • Параметр /Zc:forScope-

    Параметр компилятора /Zc:forScope- не рекомендуется к использованию и будет удален в одном из следующих выпусков.

    Command line warning  D9035: option 'Zc:forScope-' has been deprecated and will be removed in a future release
    

    Этот параметр обычно использовался, чтобы разрешить нестандартный код, использующий переменные цикла после того момента, когда, согласно стандарту, они должны выйти из области действия. Он требовался только при компиляции с параметром /Za, так как без /Za использование переменной цикла for после конца цикла всегда разрешено. Если вас не интересует соответствие стандартам (например, если код не предназначен для переноса в другие компиляторы), можно отключить параметр /Za (или задать для свойства Отключить расширения языка значение Нет). Если вы заботитесь о написании переносимого кода, соответствующего стандартам, необходимо переписать код таким образом, чтобы он соответствовал стандарту, переместив объявление таких переменных в точку за пределами цикла.

    // C2065 expected
    int main() {
        // Uncomment the following line to resolve.
        // int i;
        for (int i = 0; i < 1; i++);
        i = 20;   // i has already gone out of scope under /Za
    }
    
  • Параметр компилятора /Zg

    Параметр компилятора /Zg (создать прототипы функций) больше не доступен. Ранее этот параметр компилятора был признан нерекомендуемым.

  • Вы больше не сможете выполнять модульные тесты с использованием C++/CLI из командной строки с помощью mstest.exe. Вместо этого используйте vstest.console.exe. См. раздел VSTest.Console.exe command-line options (Параметры командной строки для VSTest.Console.exe).

  • Ключевое слово mutable

    Описатель класса хранения mutable больше нельзя использовать в местах, где ранее он компилировался без ошибок. Теперь компилятор выдает ошибку C2071 (недопустимый класс хранения). Согласно стандарту, mutable описатель может применяться только к именам членов данных класса и не может применяться к именам, объявленным константом или статическим, и не может применяться к ссылочным элементам.

    Рассмотрим следующий пример кода:

    struct S
    {
        mutable int &r;
    };
    

    Предыдущие версии компилятора принимали его, но теперь компилятор выдает следующую ошибку.

    error C2071: 'S::r': illegal storage class
    

    Чтобы устранить ошибку, удалите избыточные mutable ключевое слово.

  • char_16_t и char32_t

    Вы больше не можете использовать char16_t или char32_t как псевдонимы в объекте typedef, так как эти типы теперь рассматриваются как встроенные. Пользователи и разработчики библиотек повсеместно определяли char16_t и char32_t как псевдонимы uint16_t и uint32_t, соответственно.

    #include <cstdint>
    
    typedef uint16_t char16_t; //C2628
    typedef uint32_t char32_t; //C2628
    
    int main(int argc, char* argv[])
    {
        uint16_t x = 1; uint32_t y = 2;
        char16_t a = x;
        char32_t b = y;
        return 0;
    }
    

    Чтобы обновить код, удалите объявления и переименуйте typedef другие идентификаторы, которые сталкиваются с этими именами.

  • Параметры шаблона, не являющиеся типами

    Определенный код с параметрами шаблона, не являющимися типами, теперь правильно проверяется на совместимость типов при предоставлении явно заданных аргументов шаблона. Например, следующий код компилировался без ошибок в предыдущих версиях Visual Studio.

    struct S1
    {
        void f(int);
        void f(int, int);
    };
    
    struct S2
    {
        template <class C, void (C::*Function)(int) const> void f() {}
    };
    
    void f()
    {
        S2 s2;
        s2.f<S1, &S1::f>();
    }
    

    Текущий компилятор правильно выдает ошибку, поскольку тип параметра шаблона не соответствует аргументу шаблона (параметр является указателем на член-константу, но функция f не является константной):

    error C2893: Failed to specialize function template 'void S2::f(void)'note: With the following template arguments:note: 'C=S1'note: 'Function=S1::f'
    

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

  • __declspec(align)

    Компилятор больше не принимает __declspec(align) для функций. Эта конструкция всегда игнорировалась, но теперь вызывает ошибку компилятора.

    error C3323: 'alignas' and '__declspec(align)' are not allowed on function declarations
    

    Чтобы устранить эту проблему, удалите __declspec(align) из объявления функции. Поскольку оно не оказывает никакого влияния, его удаление ничего не меняет.

  • Обработка исключений

    Существует несколько изменений в обработке исключений. Во-первых, объекты исключений должны быть доступны для перемещения или копирования. Следующий код компилируется в Visual Studio 2013, но не в Visual Studio 2015:

    struct S
    {
    public:
        S();
    private:
        S(const S &);
    };
    
    int main()
    {
        throw S(); // error
    }
    

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

    struct S
    {
        S();
        explicit S(const S &);
    };
    
    int main()
    {
        throw S(); // error
    }
    

    Чтобы обновить код, убедитесь, что конструктор копирования для объекта public исключения не помечен explicit.

    Перехват исключения по значению также требует, чтобы объект исключения был доступен для копирования. Следующий код компилируется в Visual Studio 2013, но не в Visual Studio 2015:

    struct B
    {
    public:
        B();
    private:
        B(const B &);
    };
    
    struct D : public B {};
    
    int main()
    {
        try
        {
        }
        catch (D d) // error
        {
        }
    }
    

    Эту проблему можно устранить, изменив тип параметра для catch на ссылку.

    catch (D& d)
    {
    }
    
  • Строковые литералы с последующими макросами

    Компилятор теперь поддерживает определенные пользователем литералы. В результате строковые литералы, за которыми следуют макросы без промежуточных пробелов, интерпретируются как определенные пользователем литералы, которые могут вызывать ошибки или приводить к непредвиденным результатам. Например, в предыдущих компиляторах следующий код компилируется успешно:

    #define _x "there"
    char* func() {
        return "hello"_x;
    }
    int main()
    {
        char * p = func();
        return 0;
    }
    

    Компилятор интерпретировал этот код как строковый литерал "hello" с последующим макросом, который развертывался в "there", после чего два строковых литерала объединялись в один. В Visual Studio 2015 компилятор интерпретирует эту последовательность как определенный пользователем литерал, но поскольку соответствующий определяемый пользователем литерал _x не определен, он выдает ошибку.

    error C3688: invalid literal suffix '_x'; literal operator or literal operator template 'operator ""_x' not found
    note: Did you forget a space between the string literal and the prefix of the following string literal?
    

    Чтобы устранить эту проблему, добавьте пробел между строковым литералом и макросом.

  • Смежные строковые литералы

    Аналогично предыдущему случаю, из-за соответствующих изменений в синтаксическом анализе строк смежные строковые литералы (с широкими или узкими символами) без пробела интерпретировались в предыдущих версиях Visual C++ как одна объединенная строка. Теперь в Visual Studio 2015 необходимо добавлять пробелы между двумя строками. Например, необходимо изменить следующий код:

    char * str = "abc""def";
    

    Чтобы устранить эту проблему, добавьте пробел между двумя строками.

    char * str = "abc" "def";
    
  • Размещаемые операторы new и delete

    Для обеспечения соответствия оператору C++14 было внесено delete изменение. Сведения об изменении стандартов можно найти на странице Освобождение с размером в C++. Изменения добавляют форму глобального delete оператора, который принимает параметр размера. Критическое изменение заключается в том, что если вы ранее использовали оператор delete с той же сигнатурой (чтобы соответствовать новому оператору размещения), вы получите ошибку компилятора (C2956, которая возникает в точке, где используется новое размещение, так как это позиция в коде, где компилятор пытается определить соответствующий оператор сопоставления delete ).

    Функция void operator delete(void *, size_t) была размещаемым оператором delete, соответствующим размещаемой функции newvoid * operator new(size_t, size_t) в C++11. При размещении сделки размера C++14 эта функция удаления теперь является обычной функцией распределения сделки (глобальный delete оператор). Согласно стандарту, если использование размещаемого оператора new ищет соответствующую функцию delete и находит функции обычного освобождения, программа сформирована некорректно.

    Например, предположим, что код определяет как размещаемый оператор new, так и размещаемый оператор delete:

    void * operator new(std::size_t, std::size_t);
    void operator delete(void*, std::size_t) noexcept;
    

    Проблема возникает из-за совпадения в сигнатурах функций между определенным оператором удаления размещения и новым глобальным оператором размера delete . Рассмотрите возможность использования другого типа, отличного от size_t любого нового и оператора размещенияdelete. Тип зависимого size_ttypedef от компилятора; он предназначен typedef для unsigned int MSVC. Хорошим решением является использование перечисляемого типа, например:

    enum class my_type : size_t {};
    

    Затем измените определение размещения нового и delete используйте этот тип в качестве второго аргумента size_tвместо . Кроме того, необходимо обновить вызовы размещения нового типа для передачи нового типа (например, с помощью static_cast<my_type> преобразования из целочисленного значения) и обновить определение new и delete вернуться к целочисленным типу. Для этого не нужно использовать enum тип класса с элементом size_t .

    Альтернативным решением является возможность полного удаления размещаемого оператора new. Если код использует размещение нового для реализации пула памяти, где аргумент размещения является размером выделенного или удаленного объекта, то функция распределения размера может быть подходит для замены собственного кода пула памяти, и вы можете избавиться от функций размещения и просто использовать собственный оператор двух аргументов delete вместо функций размещения.

    Если вы не хотите немедленно обновлять код, можно вернуться к старому поведению с помощью параметра компилятора /Zc:sizedDealloc-. Если этот параметр используется, функции удаления двух аргументов не существуют и не будут вызывать конфликт с оператором удаления размещения.

  • Элементы данных объединений

    Элементы данных объединений больше не могут иметь ссылочные типы. Следующий код успешно компилируется в Visual Studio 2013, но выводит ошибку в Visual Studio 2015.

    union U1
    {
        const int i;
    };
    union U2
    {
        int & i;
    };
    union U3
    {
        struct { int & i; };
    };
    

    Предыдущий код вызывает следующие ошибки:

    test.cpp(67): error C2625: 'U2::i': illegal union member; type 'int &' is reference type
    test.cpp(70): error C2625: 'U3::i': illegal union member; type 'int &' is reference type
    

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

  • Анонимные объединения стали более полно соответствовать требованиям стандарта. Компилятор предыдущей версии создавал для анонимных объединений явный конструктор и деструктор. Эти функции, создаваемые компилятором, удалены в Visual Studio 2015.

    struct S
    {
        S();
    };
    
    union
    {
        struct
        {
            S s;
        };
    } u; // C2280
    

    Предыдущий код вызывает следующие ошибки в Visual Studio 2015:

    error C2280: '<unnamed-type-u>::<unnamed-type-u>(void)': attempting to reference a deleted function
    note: compiler has generated '<unnamed-type-u>::<unnamed-type-u>' here
    

    Чтобы устранить эту проблему, предоставьте собственные определения конструктора и/или деструктора.

    struct S
    {
        // Provide a default constructor by adding an empty function body.
        S() {}
    };
    
    union
    {
        struct
        {
            S s;
        };
    } u;
    
  • Объединения с анонимными структурами

    В целях обеспечения соответствия стандарту было изменено поведение для членов анонимных структур в объединениях. Конструктор для членов анонимных структур в объединении больше не вызывается неявно при создании такого объединения. Кроме того, деструктор для членов анонимных структур в объединении больше не вызывается неявно при выходе такого объединения из области действия. Рассмотрим следующий код, в котором объединение U содержит анонимную структуру, содержащую именованную структуру S члена с деструктором.

    #include <stdio.h>
    struct S
    {
        S() { printf("Creating S\n"); }
        ~S() { printf("Destroying S\n"); }
    };
    union U
    {
        struct {
            S s;
        };
        U() {}
        ~U() {}
    };
    
    void f()
    {
        U u;
        // Destructor implicitly called here.
    }
    
    int main()
    {
        f();
    
        char s[1024];
        printf("Press any key.\n");
        gets_s(s);
        return 0;
    }
    

    В Visual Studio 2013 конструктор для S вызывается при создании объединения, а деструктор для S вызывается при очистке стека для функции f. Однако в Visual Studio 2015 конструктор и деструктор не вызываются. Компилятор выдает предупреждение об изменении этого поведения.

    warning C4587: 'U::s': behavior change: constructor is no longer implicitly calledwarning C4588: 'U::s': behavior change: destructor is no longer implicitly called
    

    Чтобы восстановить первоначальное поведение, присвойте анонимной структуре имя. Поведение неанонимных структур во время выполнения остается прежним независимо от версии компилятора.

    #include <stdio.h>
    
    struct S
    {
        S() { printf("Creating S.\n"); }
        ~S() { printf("Destroying S\n"); }
    };
    union U
    {
        struct
        {
            S s;
        } namedStruct;
        U() {}
        ~U() {}
    };
    
    void f()
    {
        U u;
    }
    
    int main()
    {
        f();
    
        char s[1024];
        printf("Press any key.\n");
        gets_s(s);
        return 0;
    }
    

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

    #include <stdio.h>
    
    struct S
    {
        void Create() { printf("Creating S.\n"); }
        void Destroy() { printf("Destroying S\n"); }
    };
    union U
    {
        struct
        {
            S s;
        };
        U() { s.Create(); }
        ~U() { s.Destroy(); }
    };
    
    void f()
    {
        U u;
    }
    
    int main()
    {
        f();
    
        char s[1024];
        printf("Press any key.\n");
        gets_s(s);
        return 0;
    }
    
  • Разрешение шаблонов

    В разрешение имен для шаблонов были внесены изменения. При рассмотрении кандидатов для разрешения имени d C++ может возникнуть ситуация, когда одно или несколько рассматриваемых имен приводят к созданию недопустимого экземпляра шаблона. Эти недопустимые экземпляры обычно не вызывают ошибки компилятора. Данный принцип известен как SFINAE (сбой подстановки не является ошибкой).

    Если принцип SFINAE требует от компилятора создать экземпляр специализации шаблона класса, то любые ошибки, возникающие во время этого процесса, являются ошибками компилятора. В предыдущих версиях компилятор игнорирует такие ошибки. Рассмотрим следующий пример кода:

    #include <type_traits>
    
    template< typename T>
    struct S
    {
        S() = default;
        S(const S&);
        S(S& &);
    
        template< typename U, typename = typename std::enable_if< std::is_base_of< T, U> ::value> ::type>
        S(S< U> & &);
    };
    
    struct D;
    
    void f1()
    {
        S< D> s1;
        S< D> s2(s1);
    }
    
    struct B
    {
    };
    
    struct D : public B
    {
    };
    
    void f2()
    {
        S< D> s1;
        S< D> s2(s1);
    }
    

    При компиляции с помощью текущего компилятора появляется следующая ошибка:

    type_traits(1110): error C2139: 'D': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_base_of'
    ..\t331.cpp(14): note: see declaration of 'D'
    ..\t331.cpp(10): note: see reference to class template instantiation 'std::is_base_of<T,U>' being compiled
    with
    [
        T=D,
        U=D
    ]
    

    Это происходит из-за того, что при первом вызове is_base_of класс D еще не определен.

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

  • Конструкторы копии

    Как в Visual Studio 2013, так и в Visual Studio 2015, если пользователь создал в классе конструктор перемещения, но не создал конструктор копии, конструктор копии будет создан компилятором. В Dev14 этот неявно создаваемый конструктор копии также помечается как "= delete".

  • Элемент main, объявляемый с модификатором extern "C", теперь требует тип возвращаемого значения.

    Для следующего кода теперь возвращается ошибка C4430.

    extern "C" __cdecl main(){} // C4430
    

    Чтобы устранить такую ошибку, добавьте тип возвращаемого значения:

    extern "C" int __cdecl main(){} // OK
    
  • typename не может использоваться в инициализаторе члена

    Для следующего кода теперь возвращается ошибка C2059.

    template<typename T>
    struct S1 : public T::type
    {
        S1() : typename T::type() // C2059
        {
        }
    };
    
    struct S2 {
        typedef S2 type;
    };
    
    S1<S2> s;
    

    Чтобы устранить эту ошибку, удалите typename из инициализатора:

    S1() : T::type() // OK
    ...
    
  • Класс хранения игнорируется для явной специализации.

    В следующем коде игнорируется статический описатель класса хранения

    template <typename T>
    void myfunc(T h)
    {
    }
    
    template<>
    static void myfunc(double h) // static is ignored
    {
    }
    
  • Использование константы в static_assert внутри шаблона класса будет всегда приводить к ошибке.

    В следующем коде вызов static_assert всегда приводит к сбою:

    template <size_t some_value>
    struct S1
    {
        static_assert(false, "default not valid"); // always invoked
    
    };
    
    //other partial specializations here
    

    Чтобы обойти эту проблему, обтекайте значение в :struct

    template <size_t some_value>
    struct constant_false {
        static const bool value = false;
    };
    
    template <size_t some_value>
    struct S1
    {
        static_assert(constant_false<some_value>::value, "default not valid");
    };
    
    //other partial specializations here
    
  • Правила применяются для прямого объявления. (Применимо только к C.)

    Для следующего кода теперь возвращается ошибка C2065.

    struct token_s;
    typedef int BOOL;
    typedef int INT;
    
    typedef int(*PFNTERM)(PTOKEN, BOOL, INT); // C2065: 'PTOKEN' : undeclared identifier
    

    Для устранения этой проблемы добавьте соответствующие опережающие объявления:

    struct token_s;
    typedef int BOOL;
    typedef int INT;
    
    // forward declarations:
    typedef struct token_s TOKEN;
    typedef TOKEN *PTOKEN;
    
    typedef int(*PFNTERM)(PTOKEN, BOOL, INT);
    
  • Более согласованное применение типов указателей функций

    Для следующего кода теперь возвращается ошибка C2197.

    typedef int(*F1)(int);
    typedef int(*F2)(int, int);
    
    void func(F1 f, int v1, int v2)
    {
        f(v1, v2); // C2197
    }
    
  • Неоднозначные вызовы перегруженных функций

    Для следующего кода теперь возвращается ошибка C266: 'N::bind': неоднозначный вызов перегруженной функции.

    template<typename R, typename T, typename T1, typename A1>
    void bind(R(T::*)(T1), A1&&);
    
    namespace N
    {
        template <typename T, typename R, typename ... Tx>
        void bind(R(T::*)(Tx...), T* ptr);
    }
    
    using namespace N;
    
    class Manager
    {
    public:
        void func(bool initializing);
    
        void mf()
        {
            bind(&Manager::func, this); //C2668
        }
    };
    

    Чтобы устранить эту ошибку, полностью определите вызов к bind: N::bind(...). Однако если это изменение манифестируется с помощью необъявленного идентификатора (C2065), это может быть уместно для исправления этого с using объявлением.

    Такая ситуация часто возникает с ComPtr и другими типами в пространстве имен Microsoft::WRL.

  • Исправление неверного адреса

    Для следующего кода теперь возвращается ошибка C2440: "=": невозможно преобразовать "тип *" в "тип". Чтобы устранить эту ошибку, измените &(тип) на (тип) и (&f()) на (f()).

    // C
    typedef void (*type)(void);
    
    void f(int i, type p);
    void g(int);
    void h(void)
    {
        f(0, &(type)g);
    }
    
    // C++
    typedef void(*type)(void);
    
    type f();
    
    void g(type);
    
    void h()
    {
        g(&f());
    }
    
  • Строковый литерал является массивом констант

    Для следующего кода теперь создается ошибка C2664: "void f (void )": не удается преобразовать аргумент 1 из 'const char ()[2]" в "void *"

    void f(void *);
    
    void h(void)
    {
        f(&__FUNCTION__);
        void *p = &"";
    }
    

    Чтобы устранить эту ошибку, измените тип параметра функции на const void* или измените текст h, чтобы он выглядел как в следующем примере:

    void h(void)
    {
        char name[] = __FUNCTION__;
        f( name);
        void *p = &"";
    }
    
  • Строки UDL C++11

    Теперь для следующего кода создается ошибка C3688: недопустимый литеральный суффикс 'L'; литеральный оператор или литеральный шаблон оператора 'оператор ""L' не найден

    #define MACRO
    
    #define STRCAT(x, y) x\#\#y
    
    int main(){
    
        auto *val1 = L"string"MACRO;
        auto *val2 = L"hello "L"world";
    
        std::cout << STRCAT(L"hi ", L"there");
    }
    

    Чтобы устранить эту ошибку, измените код, добавив пробел:

    #define MACRO
    
    // Remove ##. Strings are automatically
    // concatenated so they aren't needed
    #define STRCAT(x, y) x y
    
    int main(){
        //Add space after closing quote
        auto *val1 = L"string" MACRO;
        auto *val2 = L"hello " L"world";
    
        std::cout << STRCAT(L"hi ", L"there");
    }
    

    В примере выше MACRO теперь не обрабатывается как два маркера (строка и макрос). Теперь он рассматривается как UDL с одним токеном. Это же правило применяется к L""L"", который ранее анализировался как L"" и L"", а теперь анализируется как L""L и "".

    Правила объединения строк также были приведены в соответствие со стандартом, что означает, что L"a" "b" эквивалентен L"ab". В предыдущих выпусках Visual Studio объединение строк с разной шириной символов не допускалось.

  • Удаление пустого символа C ++11

    Теперь для следующего кода создается ошибка C2137: Пустая символьная константа

    bool check(wchar_t c){
        return c == L''; //implicit null character
    }
    

    Чтобы устранить эту ошибку, измените код, сделав значение NULL явным:

    bool check(wchar_t c){
        return c == L'\0';
    }
    
  • Исключения MFC не могут быть перехвачены по значению, так как они не могут копироваться

    Следующий код в приложении MFC теперь вызывает ошибку C2316: 'D': не удается перехватить, поскольку деструктор и/или конструктор копии недоступен или удален

    struct B {
    public:
        B();
    private:
        B(const B &);
    };
    
    struct D : public B {
    };
    
    int main()
    {
        try
        {
        }
        catch (D) // C2316
        {
        }
    }
    

    Чтобы исправить этот код, можно изменить блок catch на catch (const D &), но обычно лучше использовать макросы MFC TRY/CATCH.

  • alignofтеперь ключевое слово

    Теперь для следующего кода создается ошибка C2332: 'класс': отсутствует имя тега. Чтобы исправить код, необходимо переименовать класс или, если класс выполняет ту же работу, что alignofи, просто замените класс новым ключевое слово.

    class alignof{}
    
  • constexprтеперь ключевое слово

    Теперь для следующего кода создается ошибка C2059: синтаксическая ошибка: ")". Чтобы исправить код, необходимо переименовать все имена функций или переменных, которые вызываются constexpr.

    int constexpr() {return 1;}
    
  • Перемещаемые типы не могут являться константами

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

  • Удаленные конструкторы копии

    Теперь для приведенного ниже кода возвращается ошибка C2280'S::S(S &&)': попытка ссылки на удаленную функцию":

    struct S{
        S(int, int);
        S(const S&) = delete;
        S(S&&) = delete;
    };
    
    S s2 = S(2, 3); //C2280
    

    Чтобы устранить эту ошибку, используйте прямую инициализацию S2:

    struct S{
        S(int, int);
        S(const S&) = delete;
        S(S&&) = delete;
    };
    
    S s2 = {2,3}; //OK
    
  • Преобразование в указатель функции создается только без лямбда-выражения

    Для следующего кода в Visual Studio 2015 создается ошибка C2664.

    void func(int(*)(int)) {}
    
    int main() {
    
        func([=](int val) { return val; });
    }
    

    Чтобы устранить эту ошибку, удалите = из списка передаваемых параметров.

  • Неоднозначные вызовы с участием операторов преобразования

    Теперь для следующего кода создается ошибка C2440: "приведение типа": невозможно преобразовать "S2" в "S1":

    struct S1 {
        S1(int);
    };
    
    struct S2 {
        operator S1();
        operator int();
    };
    
    void f(S2 s2)
    {
        (S1)s2;
    }
    

    Чтобы устранить эту ошибку, явным образом вызовите оператор преобразования:

    void f(S2 s2)
    {
        //Explicitly call the conversion operator
        s2.operator S1();
        // Or
        S1((int)s2);
    }
    

    Теперь для следующего кода создается ошибка C2593: "оператор =" является неоднозначным:

    struct S1 {};
    
    struct S2 {
        operator S1&();
        operator S1() const;
    };
    
    void f(S1 *p, S2 s)
    {
        *p = s;
    }
    

    Чтобы устранить эту ошибку, явным образом вызовите оператор преобразования:

    void f(S1 *p, S2 s)
    {
        *p = s.operator S1&();
    }
    
  • Исправление недопустимой инициализации копирования для инициализации нестатических данных-членов (NSDMI)

    Теперь для следующего кода создается ошибка C2664: 'S1::S1(S1 &&)': не удается преобразовать аргумент 1 из 'bool' в 'const S1 &':

    struct S1 {
        explicit S1(bool);
    };
    
    struct S2 {
        S1 s2 = true; // error
    };
    

    Чтобы устранить эту ошибку, используйте прямую инициализацию:

    struct S2 {
    S1 s1{true}; // OK
    };
    
  • Доступ к конструкторам внутри операторов decltype

    Для следующего кода теперь создается ошибка C2248: 'S::S': невозможно обратиться к частному члену, объявленному в классе 'S':

    class S {
        S();
    public:
        int i;
    };
    
    class S2 {
        auto f() -> decltype(S().i);
    };
    

    Чтобы исправить эту ошибку, добавьте в S объявление дружественных отношений для S2:

    class S {
        S();
        friend class S2; // Make S2 a friend
    public:
        int i;
    };
    
  • Конструктор по умолчанию для лямбда-выражения неявно удаляется

    Теперь для следующего кода создается ошибка C3497: нельзя создать экземпляр лямбда-выражения:

    void func(){
        auto lambda = [](){};
    
        decltype(lambda) other;
    }
    

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

  • Лямбда-выражения с удаленным оператором назначения

    Для следующего кода теперь возвращается ошибка C2280.

    #include <memory>
    #include <type_traits>
    
    template <typename T, typename D>
    std::unique_ptr<T, typename std::remove_reference<D &&>::type> wrap_unique(T *p, D &&d);
    
    void f(int i)
    {
        auto encodedMsg = wrap_unique<unsigned char>(nullptr, [i](unsigned char *p) {
        });
        encodedMsg = std::move(encodedMsg);
    }
    

    Чтобы устранить эту ошибку, замените лямбда-выражение классом функтора или избавьтесь от использования оператора присваивания.

  • Попытка перемещения объекта с помощью удаленного конструктора копии

    Теперь для следующего кода создается ошибка C2280: 'moveable::moveable(const moveable &)': попытка сослаться на удаленную функцию

    struct moveable {
    
        moveable() = default;
        moveable(moveable&&) = default;
        moveable(const moveable&) = delete;
    };
    
    struct S {
        S(moveable && m) :
            m_m(m)//copy constructor deleted
        {}
        moveable m_m;
    };
    

    Для устранения этой ошибки используйте оператор std::move:

    S(moveable && m) :
        m_m(std::move(m))
    
  • Локальный класс не может ссылаться на другой локальный класс, определенный позднее в той же функции

    Теперь для следующего кода создается ошибка C2079: 's' использует неопределенную структуру 'main::S2'

    int main()
    {
        struct S2;
        struct S1 {
            void f() {
                S2 s;
            }
        };
        struct S2 {};
    }
    

    Чтобы исправить эту ошибку, переместите определение S2 вверх:

    int main()
    {
        struct S2 { //moved up
        };
    
    struct S1 {
        void f() {
            S2 s;
            }
        };
    }
    
  • Невозможно вызвать защищенный базовый конструктор в теле производного конструктора.

    Для следующего кода теперь создается ошибка C2248: 'S1::S1': невозможно обратиться к частному члену, объявленному в классе 'S1':

    struct S1 {
    protected:
        S1();
    };
    
    struct S2 : public S1 {
        S2() {
            S1();
        }
    };
    

    Чтобы исправить эту ошибку, удалите из конструктора S2 вызов S1(), а при необходимости поместите его в другую функцию.

  • {} запрещает преобразование в указатель

    Для следующего кода теперь создается ошибка C2439 'S::p': не удалось инициализировать член

    struct S {
        S() : p({ 0 }) {}
        void *p;
    };
    

    Чтобы устранить ошибку, удалите фигурные скобки из области или другого 0 использования nullptr , как показано в этом примере:

    struct S {
        S() : p(nullptr) {}
        void *p;
    };
    
  • Неверное определение макросов и использование со скобками

    Для следующего примера кода теперь создается ошибка C2008: ';': не ожидается в определении макроса

    #define A; //cause of error
    
    struct S {
        A(); // error
    };
    

    Чтобы устранить эту проблему, замените код в верхней строке на #define A();

    Теперь для следующего кода создается ошибка C2059: синтаксическая ошибка: ')'.

    //notice the space after 'A'
    #define A () ;
    
    struct S {
        A();
    };
    

    Чтобы исправить этот код, удалите пробел между A и ().

    Для следующего кода создается ошибка C2091: функция возвращает функцию:

    #define DECLARE void f()
    
    struct S {
        DECLARE();
    };
    

    Чтобы устранить эту ошибку, удалите круглые скобки после DECLARE в S: DECLARE;.

    Для следующего кода создается ошибка C2062: непредвиденный тип 'int'

    #define A (int)
    
    struct S {
        A a;
    };
    

    Чтобы устранить эту проблему, определите A следующим образом:

    #define A int
    
  • Дополнительные скобки в объявлениях

    Для следующего кода создается ошибка C2062: непредвиденный тип 'int'

    struct S {
        int i;
        (int)j;
    };
    

    Чтобы устранить эту ошибку, удалите скобки вокруг j. Если скобки необходимы для ясности, используйте скобки typedef.

  • Создаваемые компилятором конструкторы и __declspec(novtable)

    В Visual Studio 2015 существует высокая вероятность, что создаваемые компилятором встроенные конструкторы абстрактных классов с виртуальными базовыми классами неправильно используют __declspec(novtable) в сочетании с __declspec(dllimport).

  • auto требует одного выражения в инициализации прямого списка

    Теперь для следующего кода создается ошибка C3518: 'testPositions': в контексте инициализации прямого списка тип 'auto' можно определить только по одному выражению инициализатора

    auto testPositions{
        std::tuple<int, int>{13, 33},
        std::tuple<int, int>{-23, -48},
        std::tuple<int, int>{38, -12},
        std::tuple<int, int>{-21, 17}
    };
    

    Чтобы устранить эту ошибку, testPositions можно инициализировать следующим образом:

    std::tuple<int, int> testPositions[]{
        std::tuple<int, int>{13, 33},
        std::tuple<int, int>{-23, -48},
        std::tuple<int, int>{38, -12},
        std::tuple<int, int>{-21, 17}
    };
    
  • Проверка типов и указателей на типы для is_convertible

    В следующем коде проверочное утверждение теперь приводит к сбою.

    struct B1 {
    private:
        B1(const B1 &);
    };
    struct B2 : public B1 {};
    struct D : public B2 {};
    
    static_assert(std::is_convertible<D, B2>::value, "fail");
    

    Чтобы устранить эту ошибку, измените static_assert так, чтобы в нем сравнивались указатели на D и B2:

    static_assert(std::is_convertible<D*, B2*>::value, "fail");
    
  • Объявления __declspec(novtable) должны быть согласованы

    Объявления __declspec должны быть согласованы во всех библиотеках. Следующий код теперь приводит к нарушению правила одного определения (ODR):

    //a.cpp
    class __declspec(dllexport)
        A {
    public:
        A();
        A(const A&);
        virtual ~A();
    private:
        int i;
    };
    
    A::A() {}
    A::~A() {}
    A::A(const A&) {}
    
    //b.cpp
    // compile with cl.exe /nologo /LD /EHsc /Osx b.cpp
    #pragma comment(lib, "A")
    class __declspec(dllimport) A
    {
    public: A();
            A(const A&);
            virtual ~A();
    private:
        int i;
    };
    
    struct __declspec(novtable) __declspec(dllexport) B
        : virtual public A {
        virtual void f() = 0;
    };
    
    //c.cpp
    #pragma comment(lib, "A")
    #pragma comment(lib, "B")
    class __declspec(dllimport) A
    {
    public:
        A();
        A(const A&);
        virtual ~A();
    private:
        int i;
    };
    struct  /* __declspec(novtable) */ __declspec(dllimport) B // Error. B needs to be novtable here also.
        : virtual public A
    {
        virtual void f() = 0;
    };
    
    struct C : virtual B
    {
        virtual void f();
    };
    
    void C::f() {}
    C c;
    

Улучшения соответствия в обновлении 1

  • Закрытые виртуальные базовые классы и косвенное наследование

    В предыдущих версиях компилятора производному классу разрешалось вызывать функции-члены косвенных базовых классов private virtual. Это поведение было неправильным и не соответствовало стандарту языка C++. Компилятор больше не принимает код, написанный таким образом, и выдает в результате ошибку C2280.

    error C2280: 'void *S3::__delDtor(unsigned int)': attempting to reference a deleted function
    

    Пример (раньше)

    class base
    {
    protected:
        base();
        ~base();
    };
    
    class middle : private virtual base {}; class top : public virtual middle {};
    
    void destroy(top *p)
    {
        delete p;  //
    }
    

    Пример (теперь)

    class base;  // as above
    
    class middle : protected virtual base {};
    class top : public virtual middle {};
    
    void destroy(top *p)
    {
        delete p;
    }
    

    - или -

    class base;  // as above
    
    class middle : private virtual base {};
    class top : public virtual middle, private virtual bottom {};
    
    void destroy(top *p)
    {
        delete p;
    }
    
  • Перегруженный оператор new и оператор delete

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

    error C2323: 'operator new': non-member operator new or delete functions may not be declared static or in a namespace other than the global namespace.
    

    Пример (раньше)

    static inline void * __cdecl operator new(size_t cb, const std::nothrow_t&)  // error C2323
    

    Пример (теперь)

    void * __cdecl operator new(size_t cb, const std::nothrow_t&)  // removed 'static inline'
    

    Кроме того, хотя компилятор не дает определенной диагностики, встроенный оператор new считается плохо сформированным.

  • Вызов "operator тип()" (пользовательское преобразование) для типов, не являющихся классами

    В предыдущих версиях компилятора допускался вызов "operator тип()" для типов, не являющихся классами, при этом он игнорировался без вывода предупреждения. Это создавало риск создания некорректного кода и непредсказуемого поведения во время выполнения. Компилятор больше не принимает код, написанный таким образом, и выдает вместо этого ошибку C2228.

    error C2228: left of '.operator type' must have class/struct/union
    

    Пример (раньше)

    typedef int index_t;
    void bounds_check(index_t index);
    void login(int column)
    {
        bounds_check(column.operator index_t());  // error C2228
    }
    

    Пример (теперь)

    typedef int index_t;
    void bounds_check(index_t index);
    void login(int column)
    {
        bounds_check(column);  // removed cast to 'index_t', 'index_t' is an alias of 'int'
    }
    
  • Избыточное ключевое слово typename в сложных спецификаторах типов

    Предыдущие версии компилятора разрешены typename в описатель сложных типов, но код, написанный таким образом, является семантической неправильной. Компилятор больше не принимает код, написанный таким образом, и выдает вместо этого ошибку C3406.

    error C3406: 'typename' cannot be used in an elaborated type specifier
    

    Пример (раньше)

    template <typename class T>
    class container;
    

    Пример (теперь)

    template <class T>  // alternatively, could be 'template <typename T>'; 'typename' is not elaborating a type specifier in this case
    class container;
    
  • Выведение типов массивов из списка инициализаторов

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

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

    error C2668: 'function' : ambiguous call to overloaded function.
    

    Пример 1. Неоднозначный вызов перегруженной функции (раньше)

    // In previous versions of the compiler, code written in this way would unambiguously call f(int, Args...)
    template < typename... Args>
    void f(int, Args...);  //
    
    template < int N, typename... Args>
    void f(const int(&)[N], Args...);
    
    int main()
    {
        // The compiler now considers this call ambiguous, and issues a compiler error
         f({ 3 });   error C2668 : 'f' ambiguous call to overloaded function
    }
    

    Пример 1. Неоднозначный вызов перегруженной функции (теперь)

    template < typename... Args>
    void f(int, Args...);  //
    
    template < int N, typename... Args>
    void f(const int(&)[N], Args...);
    
    int main()
    {
        // To call f(int, Args...) when there is just one expression in the initializer list, remove the braces from it.
        f(3);
    }
    

    Если в результате этого нового поведения при разрешении перегрузки дополнительный кандидат считается лучше ранее существовавшего, вызов разрешается однозначно в новый кандидат, что приводит к изменению поведения программы, которое, возможно, не планировалось программистом.

    Пример 2. Изменение в разрешении перегрузки (раньше)

    // In previous versions of the compiler, code written in this way would unambiguously call f(S, Args...)
    struct S
    {
        int i;
        int j;
    };
    
    template < typename... Args>
    void f(S, Args...);
    
    template < int N, typename... Args>
    void f(const int *&)[N], Args...);
    
    int main()
    {
        // The compiler now resolves this call to f(const int (&)[N], Args...) instead
         f({ 1, 2 });
    }
    

    Пример 2. Изменение в разрешении перегрузки (теперь)

    struct S;  // as before
    
    template < typename... Args>
    void f(S, Args...);
    
    template < int N, typename... Args>
    void f(const int *&)[N], Args...);
    
    int main()
    {
        // To call f(S, Args...), perform an explicit cast to S on the initializer list.
        f(S{ 1, 2 });
    }
    
  • Восстановление предупреждений, касающихся оператора switch

    Предыдущая версия компилятора удалила некоторые предупреждения, связанные с switch операторами. Теперь эти предупреждения восстановлены. Компилятор теперь выдает эти предупреждения. Предупреждения, связанные с определенными вариантами (включая вариант по умолчанию), теперь выдаются в строке, содержащей неправильный вариант, а не в последней строке оператора switch. В результате того, что теперь предупреждения выдаются не в тех строках, что раньше, предупреждения, которые ранее подавлялись с помощью #pragma warning(disable:####) , могут больше не подавляться, как планировалось. Для правильного подавления этих предупреждений может потребоваться перенести директиву #pragma warning(disable:####) в строку перед первым неправильным вариантом. Ниже приведены восстановленные предупреждения.

    warning C4060: switch statement contains no 'case' or 'default' labels
    
    warning C4061: enumerator 'bit1' in switch of enum 'flags' is not explicitly handled by a case label
    
    warning C4062: enumerator 'bit1' in switch of enum 'flags' is not handled
    
    warning C4063: case 'bit32' is not a valid value for switch of enum 'flags'
    
    warning C4064: switch of incomplete enum 'flags'
    
    warning C4065: switch statement contains 'default' but no 'case' labels
    
    warning C4808: case 'value' is not a valid value for switch condition of type 'bool'
    
    Warning C4809: switch statement has redundant 'default' label; all possible 'case' labels are given
    

    Пример предупреждения C4063 (раньше)

    class settings
    {
    public:
        enum flags
        {
            bit0 = 0x1,
            bit1 = 0x2,
            ...
        };
        ...
    };
    
    int main()
    {
        auto val = settings::bit1;
    
        switch (val)
        {
        case settings::bit0:
            break;
    
        case settings::bit1:
            break;
    
             case settings::bit0 | settings::bit1:  // warning C4063
                break;
        }
    };
    

    Пример предупреждения C4063 (теперь)

    class settings { ... };  // as above
    int main()
    {
        // since C++11, use std::underlying_type to determine the underlying type of an enum
        typedef std::underlying_type< settings::flags> ::type flags_t;
    
            auto val = settings::bit1;
    
        switch (static_cast< flags_t> (val))
        {
        case settings::bit0:
            break;
    
        case settings::bit1:
            break;
    
        case settings::bit0 | settings::bit1:  // ok
            break;
        }
    };
    

    Примеры других восстановленных предупреждений приведены в соответствующей документации.

  • #include: использование описателя родительского каталога '.' в имени пути (только влияет)/Wall/WX

    В предыдущих версиях компилятора не определялись случаи использования спецификатора parent-directory ".." в пути директив #include. Код, написанный таким образом, обычно предназначен для включения заголовков, находящихся за пределами проекта, путем неправильного использования относительных путей к проектам. Это прежнее поведение создавало риск того, что при компиляции программы мог включаться не тот файл исходного кода, который планировал программист, или что эти относительные пути невозможно было бы перенести в другие среды сборки. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет о нем программиста и выдает необязательное предупреждение C4464, если оно включено.

    warning C4464: relative include path contains '..'
    

    Пример (раньше)

    #include "..\headers\C4426.h"  // emits warning C4464
    

    Пример (теперь)

    #include "C4426.h"  // add absolute path to 'headers\' to your project's include directories
    

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

  • #pragma optimize() выходит за пределы файла заголовка (касается только /Wall/WX)

    В предыдущих версиях компилятора не определялись изменения в параметрах флагов оптимизации за пределами файла заголовка, включенного в запись преобразования. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет о нем программиста и выдает необязательное предупреждение C4426 в месте нахождения неправильного #include, если оно включено. Это предупреждение выдается только в том случае, если изменения конфликтуют с флагами оптимизации, установленными аргументами командной строки, переданными в компилятор.

    warning C4426: optimization flags changed after including header, may be due to #pragma optimize()
    

    Пример (раньше)

    // C4426.h
    #pragma optimize("g", off)
    ...
    // C4426.h ends
    
    // C4426.cpp
    #include "C4426.h"  // warning C4426
    

    Пример (теперь)

    // C4426.h
    #pragma optimize("g", off)
                ...
    #pragma optimize("", on)  // restores optimization flags set via command-line arguments
    // C4426.h ends
    
    // C4426.cpp
    #include "C4426.h"
    
  • Несоответствие #pragma warning(push) и #pragma warning(pop) (касается только /Wall/WX)

    В предыдущих версиях компилятора не обнаруживалось сопоставление изменений состояния #pragma warning(push) с изменениями состояния #pragma warning(pop) в другом файле исходного кода, которое редко бывает намеренным. Это создавало риск компиляции программы с набором включенных предупреждений, отличным от того, которое запланировал программист, что могло приводить к неправильному поведению во время выполнения. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет о нем программиста и выдает необязательное предупреждение C5031 в месте нахождения соответствующего #pragma warning(pop), если это предупреждение включено. Это предупреждение включает примечание, ссылающееся на расположение соответствующего #pragma warning(push).

    warning C5031: #pragma warning(pop): likely mismatch, popping warning state pushed in different file
    

    Пример (раньше)

    // C5031_part1.h
    #pragma warning(push)
    #pragma warning(disable:####)
    ...
    // C5031_part1.h ends without #pragma warning(pop)
    
    // C5031_part2.h
    ...
    #pragma warning(pop)  // pops a warning state not pushed in this source file
    ...
    // C5031_part1.h ends
    
    // C5031.cpp
    #include "C5031_part1.h" // leaves #pragma warning(push) 'dangling'
    ...
    #include "C5031_part2.h" // matches 'dangling' #pragma warning(push), resulting in warning C5031
    ...
    

    Пример (теперь)

    // C5031_part1.h
    #pragma warning(push)
    #pragma warning(disable:####)
    ...
    #pragma warning(pop)  // pops the warning state pushed in this source file
    // C5031_part1.h ends without #pragma warning(pop)
    
    // C5031_part2.h
    #pragma warning(push)  // pushes the warning state pushed in this source file
    #pragma warning(disable:####)
    ...
    #pragma warning(pop)
    // C5031_part1.h ends
    
    // C5031.cpp
    #include "C5031_part1.h" // #pragma warning state changes are self-contained and independent of other source files or their #include order.
    ...
    #include "C5031_part2.h"
    ...
    

    Хотя и редко, иногда код намеренно пишется таким образом. Такой код зависит от изменений в порядке #include. Мы рекомендуем, чтобы по возможности файлы исходного кода самостоятельно управляли состояниями предупреждений.

  • Несоответствие #pragma warning(push) (касается только /Wall/WX)

    В предыдущих версиях компилятора не определялось несоответствие изменений состояния #pragma warning(push) в конце записи преобразования. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет о нем программиста и выдает необязательное предупреждение C5032 в месте нахождения несоответствующего #pragma warning(push), если это предупреждение включено. Это предупреждение выдается только в том случае, если в записи преобразования нет ошибок компиляции.

    warning C5032: detected #pragma warning(push) with no corresponding #pragma warning(pop)
    

    Пример (раньше)

    // C5032.h
    #pragma warning(push)
    #pragma warning(disable:####)
    ...
    // C5032.h ends without #pragma warning(pop)
    
    // C5032.cpp
    #include "C5032.h"
    ...
    // C5032.cpp ends -- the translation unit is completed without #pragma warning(pop), resulting in warning C5032 on line 1 of C5032.h
    

    Пример (теперь)

    // C5032.h
    #pragma warning(push)
    #pragma warning(disable:####)
    ...
    #pragma warning(pop) // matches #pragma warning (push) on line 1
    // C5032.h ends
    
    // C5032.cpp
    #include "C5032.h"
    ...
    // C5032.cpp ends -- the translation unit is completed without unmatched #pragma warning(push)
    
  • В результате усовершенствования отслеживания состояния #pragma warning могут выдаваться дополнительные предупреждения

    В предыдущей версии компилятора изменения состояния #pragma warning отслеживались недостаточно хорошо для того, чтобы выдавались все необходимые предупреждения. В результате возникал риск того, что некоторые предупреждения могли подавляться в ситуациях, не предусмотренных программистом. Теперь компилятор более тщательно отслеживает состояние #pragma warning, а особенно изменения состояния #pragma warning внутри шаблонов. При необходимости он также выдает новые предупреждения C5031 и C5032, которые призваны помочь программисту в определении случаев непредусмотренного использования #pragma warning(push) и #pragma warning(pop).

    В результате усовершенствованного отслеживания изменения состояния #pragma warning теперь могут выдаваться предупреждения, которые раньше некорректно подавлялись, или предупреждения о проблемах, которые ранее диагностировались неправильно.

  • Улучшенное определение недостижимого кода

    Изменения, внесенные в стандартную библиотеку C++, и улучшенная возможность встраивания вызовов функций по сравнению с предыдущими версиями компилятора позволяют компилятору определять недостижимость определенного кода. Это может привести к тому, что предупреждение C4720 будет выдаваться чаще.

    warning C4720: unreachable code
    

    Зачастую это предупреждение выдается только при компиляции с включенными оптимизациями, так как при этом может встраиваться больше вызовов функций, удаляться избыточный код или могут производиться другие действия, позволяющие определить недостижимость определенного кода. По нашим наблюдениям, предупреждение C4720 начало часто появляться в блоках try/catch, особенно в связи с использованием std::find.

    Пример (раньше)

    try
    {
        auto iter = std::find(v.begin(), v.end(), 5);
    }
    catch (...)
    {
        do_something();   // ok
    }
    

    Пример (теперь)

    try
    {
        auto iter = std::find(v.begin(), v.end(), 5);
    }
    catch (...)
    {
        do_something();   // warning C4702: unreachable code
    }
    

Улучшения соответствия в обновлении 2

  • В результате частичной поддержки правила SFINAE для выражений могут возникать дополнительные предупреждения и ошибки

    В предыдущих версиях компилятора из-за отсутствия поддержки правила SFINAE для выражений не анализировались некоторые типы выражений внутри описателей decltype. Это поведение было неправильным и не соответствовало стандарту языка C++. В результате непрерывной оптимизации соответствия компилятор теперь анализирует эти выражения и частично поддерживает правило SFINAE для выражений. Поэтому компилятор теперь выдает предупреждения и сообщения об ошибках, найденных в выражениях, которые в предыдущих версиях компилятора не анализировались.

    Когда это новое поведение анализирует decltype выражение, которое включает тип, который еще не объявлен, компилятор выдает ошибку компилятора C2039 в результате.

    error C2039: 'type': is not a member of 'global namespace'
    

    Пример 1. Использование необъявленного типа в предыдущих версиях

    struct s1
    {
        template < typename T>
        auto f() - > decltype(s2< T> ::type::f());  // error C2039
    
        template< typename>
        struct s2 {};
    }
    

    Пример 1 в текущей версии

    struct s1
    {
        template < typename>  // forward declare s2struct s2;
    
            template < typename T>
        auto f() - > decltype(s2< T> ::type::f());
    
        template< typename>
        struct s2 {};
    }
    

    Когда новое поведение анализирует decltype выражение, которое отсутствует необходимое использование ключевое слово для указания типа зависимого typename имени, компилятор выдает предупреждение компилятора C4346 вместе с ошибкой компилятора C2923.

    warning C4346: 'S2<T>::Type': dependent name is not a type
    
    error C2923: 's1': 'S2<T>::Type' is not a valid template type argument for parameter 'T'
    

    Пример 2. Зависимое имя не является типом (в предыдущих версиях)

    template < typename T>
    struct s1
    {
        typedef T type;
    };
    
    template < typename T>
    struct s2
    {
        typedef T type;
    };
    
    template < typename T>
    T declval();
    
    struct s
    {
        template < typename T>
        auto f(T t) - > decltype(t(declval< S1< S2< T> ::type> ::type> ()));  // warning C4346, error C2923
    };
    

    Пример 2 в текущей версии

    template < typename T> struct s1 { ... };  // as above
    template < typename T> struct s2 { ... };  // as above
    
    template < typename T>
    T declval();
    
    struct s
    {
        template < typename T>
        auto f(T t) - > decltype(t(declval< S1< typename S2< T> ::type> ::type> ()));
    };
    
  • volatileПеременные-члены не допускают неявно определенных конструкторов и операторов присваивания

    В предыдущих версиях компилятора допускалось автоматическое создание конструкторов копирования и перемещения по умолчанию, а также операторов присваивания копирования и перемещения по умолчанию для класса, содержащего переменные-члены volatile. Это поведение было неправильным и не соответствовало стандарту языка C++. Компилятор теперь считает класс, имеющий volatile переменные-члены, иметь нетривиальные операторы построения и назначения, что предотвращает автоматическое создание реализаций этих операторов по умолчанию. Если такой класс является членом объединения (или анонимного объединения внутри класса), конструкторы копирования и перемещения и операторы присваивания копирования и перемещения объединения (или класса, содержащего анонимное объединение) будут неявно определены как удаленные. Попытка создать или скопировать объединение (или класс, содержащий анонимное объединение), не объявляя их явно, будет являться ошибкой. В результате будет выдана ошибка компилятора C2280.

    error C2280: 'B::B(const B &)': attempting to reference a deleted function
    

    Пример (раньше)

    struct A
    {
        volatile int i;
        volatile int j;
    };
    
    extern A* pa;
    
    struct B
    {
        union
        {
            A a;
            int i;
        };
    };
    
    B b1{ *pa };
    B b2(b1);  // error C2280
    

    Пример (теперь)

    struct A
    {
        int i; int j;
    };
    
    extern volatile A* pa;
    
    A getA()  // returns an A instance copied from contents of pa
    {
        A a;
        a.i = pa - > i;
        a.j = pa - > j;
        return a;
    }
    
    struct B;  // as above
    
    B b1{ GetA() };
    B b2(b1);  // error C2280
    
  • Статические функции-члены не поддерживают CV-квалификаторы.

    В предыдущих версиях Visual Studio 2015 допускалось наличие CV-квалификаторов у статических функций-членов. Это поведение связано с регрессией в Visual Studio 2015 и Visual Studio 2015 с обновлением 1. В компиляторе Visual Studio 2013 и более ранних версий код, написанный подобным образом, отклоняется. Такое поведение Visual Studio 2015 и Visual Studio 2015 с обновлением 1 является неправильным и не соответствует стандарту C++. Среда Visual Studio 2015 с обновлением 2 отклоняет код, написанный таким образом, и выдает вместо этого ошибку компилятора C2511.

    error C2511: 'void A::func(void) const': overloaded member function not found in 'A'
    

    Пример (раньше)

    struct A
    {
        static void func();
    };
    
    void A::func() const {}  // C2511
    

    Пример (теперь)

    struct A
    {
        static void func();
    };
    
    void A::func() {}  // removed const
    
  • Опережающее объявление перечисления недопустимо в коде WinRT (влияет только на /ZW)

    Код, скомпилированный для среда выполнения Windows (WinRT), не позволяет enum объявлять типы, аналогично тому, когда управляемый код C++ компилируется для .Net Framework с помощью коммутатора компилятора/clr. Таким образом гарантируется, что размер перечисления всегда известен и может быть правильно спрогнозирован для системы типов WinRT. Компилятор отклоняет код, написанный таким образом, и выдает ошибку компилятора C2599, а также ошибку компилятора C3197.

    error C2599: 'CustomEnum': the forward declaration of a WinRT enum is not allowed
    
    error C3197: 'public': can only be used in definitions
    

    Пример (раньше)

    namespace A {
        public enum class CustomEnum : int32;  // forward declaration; error C2599, error C3197
    }
    
    namespace A {
        public enum class CustomEnum : int32
        {
            Value1
        };
    }
    
    public ref class Component sealed
    {
    public:
        CustomEnum f()
        {
            return CustomEnum::Value1;
        }
    };
    

    Пример (теперь)

              // forward declaration of CustomEnum removed
    namespace A {
        public enum class CustomEnum : int32
        {
            Value1
        };
    }
    
    public ref class Component sealed
    {
    public:
        CustomEnum f()
        {
            return CustomEnum::Value1;
        }
    };
    
  • Встроенное объявление перегруженных операторов new и delete, не являющихся членами, невозможно (уровень 1 (/W1) включен по умолчанию)

    При встроенном объявлении функций с операторами new и delete, не являющихся членами, в предыдущих версиях компилятора не выводилось предупреждение. Код, написанный таким образом, является неверно сформированным (диагностика не требуется) и может приводить к проблемам с памятью, которые возникают в результате несоответствия операторов new и delete (особенно при совместном использовании в размерных функциях удаления) и которые может быть трудно диагностировать. Для выявления кода, написанного таким образом, компилятор теперь выдает предупреждение C4595.

    warning C4595: 'operator new': non-member operator new or delete functions may not be declared inline
    

    Пример (раньше)

    inline void* operator new(size_t sz)  // warning C4595
    {
        ...
    }
    

    Пример (теперь)

    void* operator new(size_t sz)  // removed inline
    {
        ...
    }
    

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

Улучшения соответствия в обновлении 3

  • std::is_convertable теперь обнаруживает присваивания самому себе (стандартная библиотека)

    Предыдущие версии признака типа std::is_convertable некорректно обнаруживали присваивание типа класса самому себе, когда конструктор копии удален или является закрытым. Теперь для std::is_convertable<>::value правильно задано false при применении к типу класса с удаленным или закрытым конструктором копии.

    Диагностические данные компилятора, связанные с этим изменением, отсутствуют.

    Пример

    #include <type_traits>
    
    class X1
    {
                public:
                X1(const X1&) = delete;
                };
    
    class X2
    {
                private:
                X2(const X2&);
                };
    
    static_assert(std::is_convertible<X1&, X1>::value, "BOOM");static_assert(std::is_convertible<X2&, X2>::value, "BOOM");
    

    В предыдущих версиях компилятора статические утверждения в нижней части этого примера выполнялись, так как для std::is_convertable<>::value было неправильно задано true. Теперь std::is_convertable<>::value правильно задано false, что приводит к ошибкам статических утверждений.

  • Заданные по умолчанию или удаленные упрощенные конструкторы копии и перемещения поддерживают описатели доступа

    Предыдущие версии компилятора не проверяли описатель доступа заданных по умолчанию или удаленных упрощенных конструкторов копии и перемещения перед предоставлением им возможности получать вызовы. Это поведение было неправильным и не соответствовало стандарту языка C++. В некоторых случаях это создавало риск формирования некорректного кода и непредсказуемого поведения во время выполнения. Теперь компилятор проверяет описатель доступа заданных по умолчанию или удаленных упрощенных конструкторов копии и перемещения, чтобы определить, могут ли они быть вызваны, и если нет, выдает предупреждение компилятора C2248.

    error C2248: 'S::S' cannot access private member declared in class 'S'
    

    Пример (раньше)

    class S {
    public:
        S() = default;
    private:
        S(const S&) = default;
    };
    
    void f(S);  // pass S by value
    
    int main()
    {
        S s;
        f(s);  // error C2248, can't invoke private copy constructor
    }
    

    Пример (теперь)

    class S {
    public:
        S() = default;
    private:
        S(const S&) = default;
    };
    
    void f(const S&);  // pass S by reference
    
    int main()
    {
        S s;
        f(s);
    }
    
  • Недопустимость поддержки атрибутивного кода ATL (уровень 1 (/W1) включен по умолчанию)

    Предыдущие версии компилятора поддерживали атрибутивный код ATL. На следующем этапе процесса отмены поддержки атрибутивного кода ATL, который начался в Visual Studio 2008, атрибутивный код ATL выведен из эксплуатации. Для выявления такого нерекомендуемого кода компилятор теперь выдает предупреждение C4467.

    warning C4467: Usage of ATL attributes is deprecated
    

    Если вы хотите продолжить использование атрибутивного кода ATL вплоть до отмены поддержки в компиляторе, это предупреждение можно отключить, передав аргументы командной строки /Wv:18 или /wd:4467 в компилятор или добавив #pragma warning(disable:4467) в исходный код.

    Пример 1 (раньше)

              [uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
    class A {};
    

    Пример 1 в текущей версии

    __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) A {};
    

    Иногда может потребоваться создать IDL-файл, чтобы избежать использования нерекомендуемых атрибутов ATL, как показано в следующем примере кода.

    Пример 2 (раньше)

    [emitidl];
    [module(name = "Foo")];
    
    [object, local, uuid("9e66a290-4365-11d2-a997-00c04fa37ddb")]
    __interface ICustom {
        HRESULT Custom([in] long l, [out, retval] long *pLong);
        [local] HRESULT CustomLocal([in] long l, [out, retval] long *pLong);
    };
    
    [coclass, appobject, uuid("9e66a294-4365-11d2-a997-00c04fa37ddb")]
    class CFoo : public ICustom
    {
        // ...
    };
    

    Сначала создайте файл *.idl; Созданный файл vc140.idl можно использовать для получения файла *.idl, содержащего интерфейсы и заметки.

    Затем добавьте в сборку шаг MIDL, чтобы убедиться в создании определений интерфейса C++.

    Пример 2. IDL (теперь)

    import "docobj.idl";
    
    [
        object, local, uuid(9e66a290 - 4365 - 11d2 - a997 - 00c04fa37ddb)
    ]
    
    interface ICustom : IUnknown {
        HRESULT  Custom([in] long l, [out, retval] long *pLong);
        [local] HRESULT  CustomLocal([in] long l, [out, retval] long *pLong);
    };
    
    [version(1.0), uuid(29079a2c - 5f3f - 3325 - 99a1 - 3ec9c40988bb)]
    library Foo
    {
        importlib("stdole2.tlb");
    importlib("olepro32.dll");
    [
        version(1.0),
        appobject,uuid(9e66a294 - 4365 - 11d2 - a997 - 00c04fa37ddb)
    ]
    
    coclass CFoo {
        interface ICustom;
    };
    }
    

    Затем используйте ATL непосредственно в файле реализации, как показано в следующем примере кода.

    Пример 2. Реализация (теперь)

    #include <idl.header.h>
    #include <atlbase.h>
    
    class ATL_NO_VTABLE CFooImpl :
        public ICustom,
        public ATL::CComObjectRootEx< CComMultiThreadModel>
    {
    public:
        BEGIN_COM_MAP(CFooImpl)
            COM_INTERFACE_ENTRY(ICustom)
        END_COM_MAP()
    };
    
  • Файлы предкомпилированных заголовков (PCH) и несовпадающие директивы #include (влияет только на /Wall/WX)

    Предыдущие версии компилятора принимали несовпадающие директивы #include в файлах исходного кода между компиляциями -Yc и -Yu при использовании файлов предкомпилированных заголовков (PCH). Компилятор больше не принимает код, написанный таким образом. Теперь для выявления несовпадающих директив #include при использовании PCH-файлов компилятор выдает предупреждение CC4598.

    warning C4598: 'b.h': included header file specified for Ycc.h at position 2 does not match Yuc.h at that position
    

    Пример (раньше)

    X.cpp (-Ycc.h)

    #include "a.h"
    #include "b.h"
    #include "c.h"
    

    Z.cpp (-Yuc.h)

    #include "b.h"
    #include "a.h"  // mismatched order relative to X.cpp
    #include "c.h"
    

    Пример (теперь)

    X.cpp (-Ycc.h)

    #include "a.h"
    #include "b.h"
    #include "c.h"
    

    Z.cpp (-Yuc.h)

    #include "a.h"
    #include "b.h" // matched order relative to X.cpp
    #include "c.h"
    
  • Файлы предкомпилированных заголовков (PCH) и несовпадающие каталоги include (влияет только на /Wall/WX)

    Предыдущие версии компилятора принимали аргументы командной строки несовпадающего каталога включаемых файлов (-I) в компиляторе между компиляциями -Yc и -Yu при использовании файлов предкомпилированных заголовков (PCH). Компилятор больше не принимает код, написанный таким образом. Теперь для выявления аргументов командной строки несовпадающего каталога включаемых файлов (-I) при использовании PCH-файлов компилятор выдает предупреждение CC4599.

    warning C4599: '-I..' : specified for Ycc.h at position 1 does not match Yuc.h at that position
    

    Пример (раньше)

    cl /c /Wall /Ycc.h -I.. X.cpp
    cl /c /Wall /Yuc.h Z.cpp
    

    Пример (теперь)

    cl /c /Wall /Ycc.h -I.. X.cpp
    cl /c /Wall /Yuc.h -I.. Z.cpp
    

Изменения соответствия в Visual Studio 2013

GNU C ++

  • Ключевое слово final теперь выдает ошибку неразрешенного символа в коде, который ранее компилировался без ошибок:

    struct S1 {
        virtual void f() = 0;
    };
    
    struct S2 final : public S1 {
        virtual void f();
    };
    
    int main(S2 *p)
    {
        p->f();
    }
    

    В более ранних версиях ошибка не была выдана, так как вызов был virtual вызовом. Тем не менее программа завершится сбоем во время выполнения. Теперь выдается ошибка компоновщика, поскольку известно, что класс является конечным. В этом примере для устранения ошибки нужно выполнить по компоновку объекту, который содержит определение S2::f.

  • При использовании дружественных функций в пространствах имен необходимо повторно объявить дружественную функцию, прежде чем ссылаться на нее. В противном случае возникнет ошибка, так как компилятор теперь соответствует стандарту ISO C++. Например, больше не компилируется следующий код:

    namespace NS {
        class C {
            void func(int);
            friend void func(C* const) {}
        };
    
        void C::func(int) {
            NS::func(this);  // error
        }
    }
    

    Чтобы исправить этот код, объявите функцию friend :

    namespace NS {
        class C {
            void func(int);
            friend void func(C* const) {}
        };
    
        void func(C* const);  // conforming fix
    
        void C::func(int) {
            NS::func(this);
        }
    
  • Стандарт C++ не допускает явной специализации в классе. Хотя в некоторых случаях компилятор Microsoft C++ это допускает, но в таких ситуациях, как в следующем примере, возникает ошибка, потому что компилятор не считает вторую функцию специализацией первой.

    template < int N>
    class S {
    public:
        template  void f(T& val);
        template < > void f(char val);
    };
    
    template class S< 1>;
    

    Для исправления этого кода измените вторую функцию:

    template <> void f(char& val);
    
  • Компилятор больше не пытается устранить неоднозначность между двумя функциями в следующем примере и теперь выдает ошибку.

    template< typename T> void Func(T* t = nullptr);
    template< typename T> void Func(...);
    
    int main() {
        Func< int>(); // error
    }
    

    Для исправления этого кода уточните вызов:

    template< typename T> void Func(T* t = nullptr);
    template< typename T> void Func(...);
    
    int main() {
        Func< int>(nullptr); // ok
    }
    
  • Прежде чем компилятор соответствовал ISO C++11, следующий код компилировался и вызывал x разрешение на тип int:

    auto x = {0};
    int y = x;
    

    Этот код теперь разрешает x тип std::initializer_list<int> и вызывает ошибку в следующей строке, которая пытается назначить x тип int. (По умолчанию преобразование отсутствует.) Чтобы исправить этот код, используйте int для замены auto:

    int x = {0};
    int y = x;
    
  • Агрегатная инициализация больше не допускается, если тип значения справа не соответствует типу инициализируемого значения слева. В этом случае возникает ошибка, так как стандарт ISO C++11 требует, чтобы равномерная инициализация работала без сужающих преобразований. Ранее, если сужающее преобразование было доступно, вместо ошибки выдавалось предупреждение компилятора (уровень 4) C4242.

    int i = 0;
    char c = {i}; // error
    

    Для исправления этого кода добавьте явное сужающее преобразование:

    int i = 0;
    char c = {static_cast<char>(i)};
    
  • Следующая инициализация больше не является допустимой:

    void *p = {{0}};
    

    Для исправления этого кода используйте одну из следующих форм записи:

    void *p = 0;
    // or
    void *p = {0};
    
  • Изменился поиск имен. Следующий код разрешается по-разному в компиляторе C++ в Visual Studio 2012 и Visual Studio 2013.

    enum class E1 { a };
    enum class E2 { b };
    
    int main()
    {
        typedef E2 E1;
        E1::b;
    }
    

    В Visual Studio 2012 E1 в выражении E1::b разрешается в ::E1 в глобальной области. В Visual Studio 2013 E1 в выражении E1::b разрешается в определение typedef E2 в main() и имеет тип ::E2.

  • Макет объектов изменен. В x64 макет объектов класса может отличаться от аналогичного макета в предыдущих выпусках. Если она имеет virtual функцию, но у нее нет базового класса, который имеет virtual функцию, объектная модель компилятора вставляет указатель на virtual таблицу функций после макета элемента данных. Это означает, что макет не во всех случаях будет оптимальным. В предыдущих выпусках технология оптимизации x64 предпринимала попытку улучшения макета в соответствии с требованиями пользователя, но так как при работе со сложными кодами она не выполняла свои функции должным образом, в Visual Studio 2013 данная технология была удалена. Рассмотрим для примера такой код:

    __declspec(align(16)) struct S1 {
    };
    
    struct S2 {
        virtual ~S2();
        void *p;
        S1 s;
    };
    
  • В Visual Studio 2013 результат sizeof(S2) в x64 — 48, но в предыдущих выпусках он равен 32. Чтобы сделать это значение 32 в компиляторе C++ Visual Studio 2013 для x64, добавьте фиктивный базовый класс, имеющий virtual функцию:

    __declspec(align(16)) struct S1 {
    };
    
    struct dummy {
        virtual ~dummy() {}
    };
    struct S2 : public dummy {
        virtual ~S2();
        void *p;
        S1 s;
    };
    

    Чтобы найти места в коде, которые ранее выпуска попытались бы оптимизировать, используйте компилятор из этого выпуска вместе с /W3 параметром компилятора и включите предупреждение C4370. Например:

    #pragma warning(default:4370)
    
    __declspec(align(16)) struct S1 {
    };
    
    struct S2 {
        virtual ~S2();
        void *p;
        S1 s;
    };
    

    До Visual Studio 2013 этот код выводит следующее сообщение: "Предупреждение C4370: "S2": размещение класса изменилось по сравнению с предыдущей версией компилятора из-за улучшенной упаковки".

    Проблема неоптимального макета характерна для 86-разрядного компилятора во всех его версиях. Например, если такой код компилируется для x86:

    struct S {
        virtual ~S();
        int i;
        double d;
    };
    

    Результат выражения sizeof(S) — 24. Однако это значение можно уменьшить до 16 при помощи описанного решения данной проблемы для x64:

    struct dummy {
        virtual ~dummy() {}
    };
    
    struct S : public dummy {
        virtual ~S();
        int i;
        double d;
    };
    

Стандартная библиотека

Компилятор C++ в Visual Studio 2013 обнаруживает несоответствия в _ITERATOR_DEBUG_LEVEL (функция, реализованная в Visual Studio 2010), а также несоответствия RuntimeLibrary. Эти несоответствия возникают при смешении параметров компилятора /MT (статический выпуск), /MTd (статическая отладка), /MD (динамический выпуск) и /MDd (динамическая отладка).

  • Если код признает имитируемые шаблоны псевдонима предыдущего выпуска, необходимо внести в него изменения. Например, вместо allocator_traits<A>::rebind_alloc<U>::other теперь необходимо писать allocator_traits<A>::rebind_alloc<U>. Несмотря на то, что ratio_add<R1, R2>::type больше не требуется, и теперь мы рекомендуем использовать ratio_add<R1, R2>, первый вариант по-прежнему будет компилироваться, поскольку отношение ratio<N, D> обязательно должно иметь typedef "тип" для уменьшенного отношения (то есть тот же тип, если оно уже уменьшено).

  • При вызове #include <algorithm> или std::min() необходимо использовать std::max().

  • Если существующий код использует смоделированные область перечисления предыдущего выпуска — традиционные перечисления un область d, упакованные в пространства имен, необходимо изменить его. Например, если вы ссылались на тип std::future_status::future_status, теперь необходима запись std::future_status. Однако на большую часть кода это не влияет, например std::future_status::ready по-прежнему компилируется.

  • explicit operator bool() строже, чем operator unspecified-bool-type(). explicit operator bool() разрешает явные преобразования в bool — например, при shared_ptr<X> sp и static_cast<bool>(sp) и bool b(sp) являются допустимыми — и логически проверяемые "контекстные преобразования" в bool — например if (sp), !sp, sp &&. Однако explicit operator bool() запрещает неявные преобразования в bool, поэтому нельзя написать bool b = sp;, а при возвращаемом типе bool нельзя написать return sp.

  • Теперь, когда реализованы настоящие шаблоны с переменным числом аргументов, определение препроцессора _VARIADIC_MAX и связанные с ним макросы не имеют силы. Если теперь определить _VARIADIC_MAX, это определение игнорируется. Если вы признали механизмы макросов, предназначенные для поддержки имитируемых шаблонов с переменным числом аргументов каким-либо другим способом, необходимо внести изменения в код.

  • В дополнение к обычным ключевым словам в заголовках стандартной библиотеки C++ теперь запрещена замена макросами ключевых слов override и final, связанных с контекстом.

  • reference_wrapper, ref() и cref() теперь запрещают привязку к временным объектам.

  • <random> теперь строго применяет свои предварительные условия во время компиляции.

  • Различные характеристики типов стандартной библиотеки C++ имеют предусловие "T должен быть полным типом". Несмотря на то, что теперь компилятор контролирует это предусловие более строго, он не может обеспечивать его выполнение во всех ситуациях. (Поскольку нарушение предусловия стандартной библиотеки C++ инициирует неопределенное поведение, стандарт не гарантирует принудительное применение этого предусловия.)

  • Стандартная библиотека C++ не поддерживает /clr:oldSyntax.

  • Спецификация C++11 для common_type<> имела неожиданные и нежелательные последствия; в частности, в соответствии с ней common_type<int, int>::type возвращает int&&. Таким образом, компилятор реализует предлагаемое решение для рабочей группы библиотеки 2141, что делает common_type<int, int="">::type возврат int.

    В качестве побочных эффектов этого изменения регистр удостоверения больше не работает (common_type<T> не всегда приводит к типу T). Это поведение соответствует предлагаемому разрешению, но оно нарушает любой код, зависящий от предыдущего поведения.

    Если требуется характеристика типа идентификатора, не используйте нестандартную структуру std::identity , определенную в <type_traits> , поскольку она не будет работать для <void>. Вместо этого реализуйте собственную характеристику типа идентификатора в соответствии со своими потребностями. Приведем пример:

    template < typename T> struct Identity {
        typedef T type;
    };
    

MFC и ATL

  • Только Visual Studio 2013: библиотека MFC МБ CS не включена в Visual Studio, так как Юникод настолько популярен и использование МБ CS значительно снизилось. Это изменение также обеспечивает более точное соответствие MFC самому Windows SDK, поскольку многие из новых элементов управления и сообщений поддерживают только Юникод. Однако если вы должны продолжать использовать библиотеку MFC МБ CS, ее можно скачать из Центра загрузки Майкрософт в библиотеке Multibyte MFC для Visual Studio 2013. Распространяемый пакет Visual C++ по-прежнему содержит эту библиотеку. (Примечание. Библиотека DLL MBCS входит в состав компонентов установки C++ в Visual Studio 2015 и более поздних версий.)

  • Изменился порядок доступа к ленте MFC. Вместо одноуровневой архитектуры теперь используется иерархическая архитектура. Старое поведение по-прежнему можно использовать, вызывая CRibbonBar::EnableSingleLevelAccessibilityMode().

  • Метод CDatabase::GetConnect удален. Для большей безопасности строка подключения теперь хранится в зашифрованном виде и расшифровывается только по мере необходимости. Получить строку можно с помощью метода CDatabase::Dump.

  • Подпись CWnd::OnPowerBroadcast изменена. Сигнатура этого обработчика сообщений теперь принимает LPARAM в качестве второго параметра.

  • Изменились сигнатуры для поддержки обработчиков сообщений. Списки параметров следующих функций были изменены для использования вновь добавленных обработчиков сообщений ON_WM_*:

    • Функция CWnd::OnDisplayChange изменилась с (WPARAM, LPARAM) на (UINT, int, int), чтобы можно было использовать в схеме сообщений новый макрос ON_WM_DISPLAYCHANGE.

    • Функция CFrameWnd::OnDDEInitiate изменилась с (WPARAM, LPARAM) на (CWnd*, UINT, UNIT), чтобы можно было использовать в схеме сообщений новый макрос ON_WM_DDE_INITIATE.

    • Функция CFrameWnd::OnDDEExecute изменилась с (WPARAM, LPARAM) на (CWnd*, HANDLE), чтобы можно было использовать в схеме сообщений новый макрос ON_WM_DDE_EXECUTE.

    • Функция CFrameWnd::OnDDETerminate изменилась с (WPARAM, LPARAM) на (CWnd*), чтобы можно было использовать в схеме сообщений новый макрос ON_WM_DDE_TERMINATE.

    • У функции CMFCMaskedEdit::OnCut вместо (WPARAM, LPARAM) теперь нет параметров, чтобы можно было использовать в схеме сообщений новый макрос ON_WM_CUT.

    • У функции CMFCMaskedEdit::OnClear вместо (WPARAM, LPARAM) теперь нет параметров, чтобы можно было использовать в схеме сообщений новый макрос ON_WM_CLEAR.

    • У функции CMFCMaskedEdit::OnPaste вместо (WPARAM, LPARAM) теперь нет параметров, чтобы можно было использовать в схеме сообщений новый макрос ON_WM_PASTE.

  • Директивы #ifdef в файлах заголовков MFC удалены. Многочисленные #ifdef директивы в файлах заголовков MFC, связанных с неподдерживаемых версий Windows (WINVER < 0x0501) удаляются.

  • Удалена библиотека ATL DLL (atl120.dll). ATL теперь предоставляется в виде заголовков и статической библиотеки (atls.lib).

  • Удалены библиотеки atlsd.lib, atlsn.lib и atlsnd.lib. Библиотека Atls.lib больше не имеет зависимостей от кодировки или кода, относящегося исключительно к отладке или выпуску. Поскольку она работает одинаково для Юникода/ANSI и отладки/выпуска, достаточно одной версии библиотеки.

  • Средство трассировки ATL/MFC удалено вместе с DLL-библиотекой ATL, и механизм трассировки упрощен. Конструктор CTraceCategory теперь принимает один параметр (имя категории), а макросы TRACE вызывают функции отчетов отладки CRT.

Критические изменения в Visual Studio 2012

GNU C ++

  • Параметр компилятора /Yl был изменен. По умолчанию компилятор использует этот параметр, который при определенных условиях может привести к ошибкам LNK2011. Дополнительные сведения см. в статье /Yl (Inject PCH Reference for Debug Library) (Параметр /Yl (вставка ссылки на PCH-файл для библиотеки отладки) (C++)).

  • В коде, скомпилированном с помощью/clr, enum класс ключевое слово определяет перечисление C++11, а не перечисление среды CLR. Чтобы определить перечисление CLR, необходимо явно указать его доступность.

  • Используйте шаблон ключевое слово для явной диамбигуации зависимого имени (соответствие языка C++ standard). В следующем примере ключевое слово выделенного шаблона необходимо, чтобы устранить неоднозначность. Дополнительные сведения см. в разделе Разрешение имен для зависимых типов.

    template < typename X = "", typename = "" AY = "">
    struct Container { typedef typename AY::template Rebind< X> ::Other AX; };
    
  • Константное выражение типа float больше не поддерживается как аргумент шаблона, как показано в следующем примере.

    template<float n=3.14>
    struct B {};  // error C2993: 'float': illegal type for non-type template parameter 'n'
    
  • Код, который компилируется с помощью параметра командной строки /GS и имеет одну уязвимость, может привести к завершению процесса во время выполнения, как показано в следующем примере псевдокода.

    char buf[MAX]; int cch; ManipulateString(buf, &cch); // ... buf[cch] = '\0'; // if cch >= MAX, process will terminate
    
  • По умолчанию архитектура сборки x86 изменена на SSE2. Таким образом, компилятор может создавать инструкции SSE и будет использовать регистры XMM для выполнения вычислений с плавающей запятой. Если вы хотите вернуться к предыдущему поведению, используйте флаг компилятора /arch:IA32 для указания архитектуры как IA32.

  • Компилятор может выдавать предупреждения Предупреждение компилятора (уровень 4) C4703, а ранее в C4701 этого не было. Компилятор применяет более строгие проверки для использования неинициализированных локальных переменных типа указателя.

  • Когда установлен новый флаг компоновщика /HIGHENTROPYVA, Windows 8 обычно при выделении памяти возвращает 64-разрядный адрес. (До Windows 8 такие выделения чаще возвращают адреса, которые были менее 2 ГБ.) Это изменение может предоставлять ошибки усечения указателя в существующем коде. По умолчанию этот параметр включен. Значение /HIGHENTROPYVA:NO отключает это поведение.

  • Управляемый компилятор (Visual Basic или C#) также поддерживает /HIGHENTROPYVA для управляемых сборок. Однако в этом случае параметр /HIGHENTROPYVAswitch отключен по умолчанию.

IDE

  • Хотя рекомендуется не создавать приложения Windows Forms в C++/CLI, поддерживается обслуживание существующих приложений пользовательского интерфейса C++/CLI. Если необходимо создать приложение Windows Forms или любое другое приложение пользовательского интерфейса .NET, используйте C# или Visual Basic. Используйте C++/CLI только в целях взаимодействия.

Библиотека параллельных шаблонов и библиотека среды выполнения с параллелизмом

Перечисление SchedulerTypeUmsThreadDefault является устаревшим. Спецификация UmsThreadDefault выдает предупреждение о нерекомендуемом использовании и внутренне сопоставляется с ThreadScheduler.

Стандартная библиотека

  • После критических изменений между стандартами C++98/03 и C++11 код, использующий явное указание шаблонных аргументов для вызова make_pair(), как, например, в make_pair<int, int>(x, y), обычно не компилируется в Visual C++ в Visual Studio 2012. Решение заключается в том, чтобы всегда вызывать make_pair() без явных аргументов шаблона , как и в make_pair(x, y). Предоставление явно заданных аргументов шаблона уничтожает назначение функции. Если требуется точный контроль над результирующим типом, используйте pair вместо make_pair — как в pair<short, short>(int1, int2).

  • Еще одно критическое изменение между стандартами C++98/03 и C++11: если A неявно преобразуется в B и B неявно преобразуется в C, но A неявно преобразуется в C, C++98/03 и Visual Studio 2010 разрешено pair<A, X> преобразовать (неявно или явно) pair<C, X>в . (Другой тип, X, не является интересом здесь, и не зависит от первого типа в паре.) Компилятор C++ в Visual Studio 2012 обнаруживает, что A неявно преобразуется в C и удаляет преобразование пары из разрешения перегрузки. Это изменение является положительным во многих ситуациях. Например, перегрузка func(const pair<int, int>&) и func(const pair<string, string>&) и вызов func() с pair<const char *, const char *> будет компилироваться в результате этого изменения. Однако это изменение нарушает код, основанный на агрессивных преобразованиях пар. Такой код обычно может быть исправлен выполнением одной из частей преобразования явно, например путем передачи make_pair(static_cast<B>(a), x) в функцию, ожидающую pair<C, X>.

  • Visual Studio 2010 имитировала variadic-шаблоны (шаблоны с переменным числом аргументов), например make_shared<T>(arg1, arg2, argN), с ограничением до 10 аргументов, маркируя перегрузки и специализации с помощью аппаратных ресурсов процессора. В Visual Studio 2012 это ограничение уменьшено до пяти аргументов, чтобы улучшить время компиляции и использование памяти компилятора для большинства пользователей. Однако можно задать предыдущее ограничение, явно определяя _VARIADIC_MAX как 10, для всего проекта.

  • C++ 11 17.6.4.3.1 [macro.names]/2 запрещает замену ключевых слов макросами, если включены заголовки стандартной библиотеки C++. Теперь заголовки выдают ошибки компилятора при обнаружении ключевых слов, замененных макросами. (Определение _ALLOW_KEYWORD_MACROS позволяет компилировать такой код, но настоятельно не рекомендуется использовать этот код.) Как исключение, макроформа new разрешена по умолчанию, так как заголовки полностью защищают себя с помощью/#pragma push_macro("new")#undef new/#pragma pop_macro("new"). Определение _ENFORCE_BAN_OF_MACRO_NEW делает именно то, что предполагает его имя.

  • Для реализации новых способов оптимизации и проверки результатов отладки стандартная библиотека C++, представленная в Visual Studio, намеренно ограничивает совместимость двоичных данных между версиями Visual Studio (2005, 2008, 2010, 2012). Поэтому при использовании стандартной библиотеки C++ файлы объектов и статические библиотеки, скомпилированные с помощью разных версий, нельзя одновременно добавить в один двоичный файл (EXE или DLL), а объекты стандартной библиотеки C++ нельзя передать из одного двоичного файла в другой, если эти файлы скомпилированы с помощью разных версий. Смешивание файлов объектов и статических библиотек (использующих стандартную библиотеку C++), одни из которых были скомпилированы с помощью Visual Studio 2010, а другие — с помощью компилятора C++ в Visual Studio 2012, вызывает ошибки компоновщика о несоответствии _MSC_VER, где _MSC_VER является макросом, содержащим основной номер версии компилятора (1700 для Visual C++ в Visual Studio 2012). Эта проверка не может обнаружить смешение DLL и смешение, в котором участвует Visual Studio 2008 или более ранних версий.

  • Наряду с обнаружением несоответствия в _ITERATOR_DEBUG_LEVEL (функция, реализованная в Visual Studio 2010) компилятор C++ в Visual Studio 2012 обнаруживает несоответствия библиотеки времени выполнения. Эти несоответствия возникают при смешении параметров компилятора /MT (статический выпуск), /MTd (статическая отладка), /MD (динамический выпуск) и /MDd (динамическая отладка).

  • operator<(), operator>(), operator<=() и operator>=() ранее были доступны для семейств контейнеров std::unordered_map и stdext::hash_map, несмотря на то, что их реализации не были полезными. Эти нестандартные операторы были удалены в Visual C++ в Visual Studio 2012. Кроме того, реализация operator==() и operator!=() для семейства std::unordered_map была расширена и теперь включает в себя семейство stdext::hash_map. (Рекомендуется избегать использования семейства stdext::hash_map в новом коде.)

  • C++ 11 22.4.1.4 [locale.codecvt] указывает, что codecvt::length() и codecvt::do_length() должны принимать изменяемые параметры stateT&, но Visual Studio 2010 принимала const stateT&. Компилятор C++ в Visual Studio 2012 принимает stateT& в соответствии со стандартом. Это различие важно для всех, кто пытается переопределить виртуальную функцию do_length().

CRT - библиотека

  • Куча среды выполнения C (CRT), которая используется для new и malloc(), больше не является закрытой. CRT теперь использует кучу процесса. Это означает, что куча не уничтожается при выгрузке библиотеки DLL, поэтому библиотеки DLL, которые связывают статически с CRT, должны обеспечить очистку памяти, выделенной кодом DLL перед выгрузкой.

  • Функция iscsymf() подтверждает с отрицательными значениями.

  • Структура threadlocaleinfostruct была изменена в соответствии с изменениями функций языкового стандарта.

  • Функции CRT, имеющие соответствующие встроенные функции, такие как memxxx(), strxxx(), удалены из intrin.h. Если файл включен intrin.h только для этих функций, теперь необходимо включить соответствующие заголовки CRT.

MFC и ATL

  • Удалена поддержка Fusion (afxcomctl32.h); следовательно, все методы, определенные в <afxcomctl32.h> них, были удалены. Файлы <afxcomctl32.h> заголовков и <afxcomctl32.inl> удалены.

  • Изменено имя CDockablePane::RemoveFromDefaultPaneDividier на CDockablePane::RemoveFromDefaultPaneDivider.

  • Сигнатура CFileDialog::SetDefExt изменена для использования LPCTSTR, поэтому затронуты сборки Юникода.

  • Удалены устаревшие категории трассировки ATL.

  • Изменена сигнатура CBasePane::MoveWindow, чтобы принимать const CRect.

  • Изменена сигнатура CMFCEditBrowseCtrl::EnableBrowseButton.

  • Удалено m_fntTabs и m_fntTabsBold из CMFCBaseTabCtrl.

  • Добавлен параметр в конструкторы CMFCRibbonStatusBarPane. (Это параметр по умолчанию, поэтому он не нарушает код.)

  • Добавлен параметр в конструктор CMFCRibbonCommandsListBox. (Это параметр по умолчанию, поэтому он не нарушает код.)

  • Удален API AFXTrackMouse (и связанный таймер proc). Вместо него используйте API Win32 TrackMouseEvent.

  • Добавлен параметр в конструктор CFolderPickerDialog. (Это параметр по умолчанию, поэтому он не нарушает код.)

  • Изменен размер структуры CFileStatus: элемент m_attribute изменен с BYTE на DWORD (для соответствия значению, возвращенному GetFileAttributes).

  • CRichEditCtrl и CRichEditView используют MSFTEDIT_CLASS (элемент управления RichEdit 4.1) вместо RICHEDIT_CLASS (элемент управления RichEdit 3.0) в сборках Юникода.

  • Удален AFX_GLOBAL_DATA::IsWindowsThemingDrawParentBackground, так как он всегда имеет значение TRUE в Windows Vista, Windows 7 и Windows 8.

  • Удален AFX_GLOBAL_DATA::IsWindowsLayerSupportAvailable, так как он всегда имеет значение TRUE в Windows Vista, Windows 7 и Windows 8.

  • Удален AFX_GLOBAL_DATA::DwmExtendFrameIntoClientArea. Вызывайте Windows API непосредственно в Windows Vista, Windows 7 и Windows 8.

  • Удален AFX_GLOBAL_DATA::DwmDefWindowProc. Вызывайте Windows API непосредственно в Windows Vista, Windows 7 и Windows 8.

  • AFX_GLOBAL_DATA::DwmIsCompositionEnabled переименован в IsDwmCompositionEnabled во избежание конфликта имен.

  • Изменены идентификаторы для ряда внутренних таймеров MFC и перемещены определения в afxres.h (AFX_TIMER_ID_ *).

  • Изменена сигнатура метода OnExitSizeMove для соответствия макросу ON_WM_EXITSIZEMOVE:

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

  • Изменены имя и сигнатура метода OnDWMCompositionChanged для соответствия макросу ON_WM_DWMCOMPOSITIONCHANGED:

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

  • Изменена сигнатура метода OnMouseLeave для соответствия макросу ON_WM_MOUSELEAVE:

    • CMFCCaptionBar

    • CMFCColorBar

    • CMFCHeaderCtrl

    • CMFCProperySheetListBox

    • CMFCRibbonBar

    • CMFCRibbonPanelMenuBar

    • CMFCRibbonRichEditCtrl

    • CMFCSpinButtonCtrl

    • CMFCToolBar ReplaceThisText

    • CMFCToolBarComboBoxEdit

    • CMFCToolBarEditCtrl

    • CMFCAutoHideBar

  • Изменена сигнатура OnPowerBroadcast для соответствия макросу ON_WM_POWERBROADCAST:

    • CFrameWndEx

    • CMDIFrameWndEx

  • Изменена сигнатура OnStyleChanged для соответствия макросу ON_WM_STYLECHANGED:

    • CMFCListCtrl

    • CMFCStatusBar

  • Внутренний метод FontFamalyProcFonts переименован в FontFamilyProcFonts.

  • Удалены многочисленные глобальные статические объекты CString во избежание утечки памяти в некоторых ситуациях (заменены на #defines) и следующие переменные-члены класса:

    • CKeyBoardManager::m_strDelimiter

    • CMFCPropertyGridProperty::m_strFormatChar

    • CMFCPropertyGridProperty::m_strFormatShort

    • CMFCPropertyGridProperty::m_strFormatLong

    • CMFCPropertyGridProperty::m_strFormatUShort

    • CMFCPropertyGridProperty::m_strFormatULong

    • CMFCPropertyGridProperty::m_strFormatFloat

    • CMFCPropertyGridProperty::m_strFormatDouble

    • CMFCToolBarImages::m_strPngResType

    • CMFCPropertyGridProperty::m_strFormat

  • Изменена сигнатура CKeyboardManager::ShowAllAccelerators и удален параметр разделителя сочетаний клавиш.

  • Добавлен метод CPropertyPage::GetParentSheet. Его следует вызывать в классе CPropertyPage вместо GetParent для возврата правильного родительского окна таблицы, которое может быть родителем или прародителем окна CPropertyPage. Для вызова GetParentSheet вместо GetParent может потребоваться изменить код.

  • Исправлено несбалансированное #pragma warning(push) в ATLBASE. H, которое неправильно отключало предупреждения. Теперь после проверки ATLBASE.H предупреждения включены правильно.

  • Методы, связанные с D2D, перемещены из AFX_GLOBAL_DATA в _AFX_D2D_STATE:

    • GetDirectD2dFactory

    • GetWriteFactory

    • GetWICFactory

    • InitD2D

    • ReleaseD2DRefs

    • IsD2DInitialized

    • D2D1MakeRotateMatrix

    • Например, вместо вызова afxGlobalData.IsD2DInitialized вызовите AfxGetD2DState->IsD2DInitialized.

  • Удалить устаревшие CPP-файлы ATL из папки \atlmfc\include\.

  • Инициализация afxGlobalData выполняется по запросу, а не во время инициализации CRT, чтобы удовлетворить требованиям DLLMain.

  • Добавлен метод RemoveButtonByIndex в класс CMFCOutlookBarPane.

  • CMFCCmdUsageCount::IsFreqeuntlyUsedCmd исправлено на IsFrequentlyUsedCmd.

  • Исправлено несколько экземпляров RestoreOriginalstate на RestoreOriginalState (CMFCToolBar, CMFCMenuBar, CMFCOutlookBarPane).

  • Удалены неиспользуемые методы из CDockablePane: SetCaptionStyle, IsDrawCaption, IsHideDisabledButtons, GetRecentSiblingPaneInfo и CanAdjustLayout.

  • Удалены статические переменные-члены CDockablePanem_bCaptionText и m_bHideDisabledButtons.

  • Добавлен метод переопределения DeleteString в CMFCFontComboBox.

  • Удалены неиспользуемые методы из CPane: GetMinLength и IsLastPaneOnLastRow.

  • CPane::GetDockSiteRow(CDockingPanesRow *) переименован в CPane::SetDockSiteRow.

Критические изменения в Visual Studio 2010

GNU C ++

  • Ключевое слово auto имеет новое значение по умолчанию. Поскольку старое значение используется редко, на большинство приложений это изменение не окажет влияния.

  • Появилась новая static_assert ключевое слово, которая приведет к конфликту имен, если в коде уже есть идентификатор.

  • Поддержка новой лямбда-нотации исключает поддержку указания в коде GUID без кавычек в атрибуте uuid IDL.

  • .NET Framework 4 вводит концепцию исключений поврежденных состояний — исключений, оставляющих процесс в состоянии неустранимых повреждений. По умолчанию невозможно перехватить исключение поврежденного состояния даже с помощью параметра компилятора /EHa, который перехватывает все прочие исключения. Чтобы явно поймать поврежденное исключение состояния, используйте инструкции __try-__except. Или примените атрибут [HandledProcessCorruptedStateExceptions], чтобы включить функцию перехвата исключений поврежденного состояния. Это изменение влияет главным образом на системных программистов, которым может потребоваться перехватить исключение поврежденного состояния. Восемь исключений: STATUS_ACCESS_VIOLATION, STATUS_STACK_OVERFLOW, EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_IN_PAGE_ERROR, EXCEPTION_INVALID_DISPOSITION, EXCEPTION_NONCONTINUABLE_EXCEPTION, EXCEPTION_PRIV_INSTRUCTION, STATUS_UNWIND_CONSOLIDATE. Дополнительные сведения об этих исключениях см. в разделе о макросе GetExceptionCode.

  • Измененный параметр компилятора /GS предотвращает переполнение буфера более комплексно, чем в предыдущих версиях. Эта версия может включать в стек дополнительные проверки безопасности, которые могут отрицательно сказываться на общей производительности. Используйте новое ключевое слово __declspec(safebuffers), чтобы указать компилятору на то, что не следует вставлять проверки безопасности для конкретной функции.

  • При одновременном использовании параметров компилятора /GL (оптимизация всей программы) и /clr (компиляция CLR) параметр /GL игнорируется. Это изменение внесено по той причине, что использование сочетания параметров компилятора было малоэффективным. В результате изменения повысилась производительность сборки.

  • По умолчанию поддержка триграфов в Visual Studio 2010 отключена. Для включения поддержки триграфов используйте параметр компилятора /Zc:trigraphs. Триграф состоит из двух последовательных вопросительных знаков ("??"), за которыми следует третий уникальный знак. Компилятор заменяет триграф соответствующим знаком пунктуации. Например, компилятор заменяет триграф ??= на символ "#". Триграфы следует использовать в файлах исходного кода на С, которые имеют кодировку, не содержащую подходящего графического представления для некоторых знаков пунктуации.

  • Компоновщик больше не поддерживает оптимизацию для Windows 98. Параметр /OPT (оптимизации) вызывает ошибку времени компиляции, если указать /OPT:WIN98 или /OPT:NOWIN98.

  • Параметры компилятора по умолчанию, указываемые свойствами системы построения RuntimeLibrary и DebugInformationFormat, изменены. По умолчанию эти свойства построения указываются в проектах, созданных с помощью Visual C++ выпусков 7.0–10.0. При миграции проекта, созданного с помощью Visual C++ выпуска 6.0, продумайте, имеет ли смысл указать значения этих свойств.

  • В Visual Studio 2010 RuntimeLibrary = MultiThreaded (/MD), а DebugInformationFormat = ProgramDatabase (/Zi). Visual C++ 9.0 RuntimeLibrary = MultiThreaded (/MT), а DebugInformationFormat = Disabled.

CLR

  • Компиляторы Microsoft C# и Visual Basic теперь могут создавать неосновную сборку взаимодействия (no-PIA). Сборка no-PIA может использовать типы COM без развертывания связанной с ними основной сборки взаимодействия (PIA). При использовании сборок no-PIA, созданных в Visual C# или Visual Basic, необходимо ссылаться на сборку PIA в команде компилятора до ссылки на какие-либо сборки no-PIA, использующие библиотеку.

Проекты Visual Studio C++ и MSBuild

  • Проекты Visual Studio C++ теперь основываются на средстве MSBuild. Следовательно, файлы проекта используют новый формат XML-файла и суффикс файла .vcxproj. Visual Studio 2010 автоматически преобразует файлы проекта более ранней версии Visual Studio в новый формат файла. На существующий проект оказывается влияние, если он зависим от ранее использовавшегося средства построения, VCBUILD.exe или файла проекта с суффиксом .vcproj.

  • В более ранних версиях язык Visual C++ поддерживал позднее использование страниц свойств. Например, родительская страница свойств может импортировать дочернюю страницу свойств и использовать переменную, определенную в дочернем элементе, для определения других переменных. Позднее использование позволяет родителю использовать дочернюю переменную еще до импорта дочерней страницы свойств. В Visual Studio2010 переменную страницы проекта нельзя использовать, пока она не определена, потому что MSBuild поддерживает только раннюю оценку.

IDE

  • Диалоговое окно завершения приложения теперь не завершает приложение. В предыдущих выпусках, когда функция abort() или terminate() завершала коммерческое построение приложения, библиотека времени выполнения языка С отображала сообщение о завершении работы приложения в окне консоли или в диалоговом окне. В сообщении указывалось: "Приложение потребовало от среды выполнения завершить работу ненормальным образом. Обратитесь в службу поддержки приложения, чтобы получить дополнительные сведения". Сообщение о завершении приложения было избыточным, так как в Windows впоследствии отображался текущий обработчик завершения, который обычно был диалоговым окном отчеты об ошибках Windows (д-р Уотсон) или отладчиком Visual Studio. Начиная с версии Visual Studio 2010 библиотека времени выполнения языка С не выводит это сообщение. Более того, среда выполнения не допускает завершение работы приложения до запуска отладчика. Это критическое изменение ощутимо только в том случае, если есть зависимость от прежнего поведения сообщения о завершении приложения.

  • В частности, в Visual Studio 2010 IntelliSense не работает с кодами или атрибутами C++/CLI, команда Найти все ссылки не работает с локальными переменными, а функция "Модель кода" не извлекает имена типов из импортированных сборок и не разрешает типы в их полные имена.

Библиотеки

  • Класс SafeInt включен в Visual C++, и более нет необходимости в его отдельной загрузке. Это изменение может вызвать трудности, только если у вас есть собственный класс с именем SafeInt.

  • Модель развертывания библиотек больше не использует манифесты для поиска конкретной версии библиотеки динамической компоновки (DLL). Вместо этого имя каждой динамической библиотеки компоновки содержит номер версии, это имя и используется для поиска библиотеки.

  • В предыдущих версиях Visual Studio можно было перестраивать библиотеки времени выполнения. Visual Studio2010 больше не поддерживает построение собственных копий файлов библиотеки времени выполнения C.

Стандартная библиотека

  • Заголовок <iterator> больше не включается автоматически многими другими файлами заголовков. Вместо этого заголовок необходимо включать явно, если требуется поддержка отдельных итераторов, определенных в заголовке. Существующий проект затрагивается, если он зависит от предыдущего средства сборки VCBUILD.exe или файла проекта с суффиксом .vcproj.iterator.

  • В заголовке <algorithm>checked_* удаляются функции и unchecked_* функции. И в заголовке <iterator>>checked_iterator класс удаляется, и unchecked_array_iterator класс был добавлен.

  • Конструктор CComPtr::CComPtr(int) удален. Этот конструктор позволял построить объект CComPtr при помощи макроса NULL, но был не нужен и допускал бессмысленные конструкции из ненулевых целых чисел.

    CComPtr может быть построен при помощи макроса NULL, который определен как 0, но допустит ошибку, если будет строиться из целого числа, отличного от 0. Вместо этого используйте nullptr.

  • Следующие функции-члены ctype были удалены: ctype::_Do_narrow_s, ctype::_Do_widen_s, ctype::_narrow_s, ctype::_widen_s. Если в приложении используется одна или несколько из этих функций-членов, необходимо заменить их на соответствующие небезопасные версии: ctype::do_narrow, ctype::do_widen, ctype::narrow, ctype::widen.

Библиотеки ATL, MFC и CRT

  • Удалена поддержка построения библиотек CRT, MFC и ATL пользователями. Например, отсутствует файл NMAKE. Однако пользователи по-прежнему имеют доступ к исходному коду этих библиотек. Документ, описывающий параметры MSBuild, используемые корпорацией Майкрософт для построения этих библиотек, вероятно, будет опубликован в блоге группы разработчиков Visual C++.

  • Удалена поддержка MFC для IA64. Однако по-прежнему предоставляется поддержка для CRT и ATL с IA64.

  • В файлах определения модулей (DEF) библиотеки MFC порядковые числа больше не используются многократно. Это изменение означает, что порядковые номера не будут отличаться в дополнительных версиях и будет улучшена двоичная совместимость пакетов обновления и выпусков исправлений QFE.

  • В класс CDocTemplate добавлена новая виртуальная функция. Это функция CDocTemplate — класс. У предыдущей версии OpenDocumentFile было два параметра. У новой версии три параметра. Чтобы класс, производный от CDocTemplate, поддерживал диспетчер перезапуска, в нем должна быть реализована версия с тремя параметрами. Новый параметр — bAddToMRU.

Макросы и переменные среды

  • Переменная среды __MSVCRT_HEAP_SELECT больше не поддерживается. Эта переменная среды удалена, и замена ей не предусмотрена.

Справочные материалы по ассемблеру Microsoft Macro Assembler

  • Некоторые директивы были удалены из компилятора справочных материалов по ассемблеру Microsoft Macro Assembler. Удаленные директивы: .186, .286, .286P, .287, .8086, .8087 и .NO87.

Критические изменения в Visual Studio 2008

GNU C ++

  • Платформы Windows 95, Windows 98, Windows ME и Windows NT больше не поддерживаются. Эти операционные системы были удалены из списка целевых платформ.

  • Компилятор больше не поддерживает некоторые атрибутов, которые были непосредственно связаны с сервером ATL. Следующие атрибуты больше не поддерживаются:

    • perf_counter

    • perf_object

    • perfmon

    • request_handler

    • soap_handler

    • soap_header

    • soap_method

    • tag_name

Проекты Visual Studio C++

  • При обновлении проектов из предыдущих версий Visual Studio необходимо изменить макросы WINVER и _WIN32_WINNT так, чтобы они были не меньше значения 0x0500.

  • Начиная с версии Visual Studio 2008 мастер создания проектов не поддерживает возможность создания проекта C++ SQL Server. Проекты SQL Server, созданные в более ранней версии Visual Studio, компилируются и работают правильно.

  • Файл заголовка Winable.h Windows API был удален. Вместо него следует использовать файл WinUser.h.

  • Библиотека Rpcndr.lib Windows API была удалена. Вместо нее следует использовать библиотеку rpcrt4.lib.

CRT - библиотека

  • Удалена поддержка для Windows 95, Windows 98, Windows Millennium Edition и Windows NT 4.0.

  • Были удалены следующие глобальные переменные:

    • _osplatform

    • _osver

    • _winmajor

    • _winminor

    • _winver

  • Были удалены следующие функции. Вместо этого используйте функции API Windows GetVersion или GetVersionEx:

    • _get_osplatform

    • _get_osver

    • _get_winmajor

    • _get_winminor

    • _get_winver

  • Изменился синтаксис для примечаний SAL. Дополнительные сведения см. в статье SAL Annotations (Примечания SAL).

  • Фильтр IEEE теперь поддерживает набор инструкций SSE 4.1. Дополнительные сведения см. в статье _fpieee_flt_fpieee_flt.

  • Библиотеки времени выполнения C, поставляемые с Visual Studio, больше не зависят от системной DLL msvcrt.dll.

Стандартная библиотека

  • Удалена поддержка для Windows 95, Windows 98, Windows Millennium Edition и Windows NT 4.0.

  • При компиляции в режиме отладки с определенным _HAS_ITERATOR_DEBUGGING (заменен на _ITERATOR_DEBUG_LEVEL после Visual Studio 2010) приложение будет подтверждать, когда итератор пытается увеличить или уменьшить границы базового контейнера.

  • Переменная-член c класса stack теперь объявляется как защищенная. Ранее эта переменная-член объявлялась как открытая.

  • Поведение money_get::do_get было изменено. Ранее при синтаксическом анализе денежной суммы с большим количеством цифр после запятой, чем вызывал frac_digits, do_get использовал их все. Теперь do_get прекращает разбор после использования максимального числа символов frac_digits.

ATL

  • Невозможно выполнить сборку ATL без зависимости от CRT. В более ранних версиях Visual Studio можно было использовать #define ATL_MIN_CRT, чтобы установить минимальную зависимость проекта ATL от CRT. В Visual Studio 2008 все проекты ATL минимально зависят от CRT независимо от того, определен ли ATL_MIN_CRT.

  • База кода сервера ATL была выпущена в виде проекта с общим исходным кодом в CodePlex и не устанавливается как часть Visual Studio. Классы кодирования и декодирования данных из файла atlenc.h и служебных функций и классы из файлов atlutil.h и atlpath.h сохранились и теперь входят в библиотеку ATL. Некоторые файлы, связанные с сервером ATL, больше не являются частью Visual Studio.

  • Некоторые функции больше не входят в библиотеку DLL. Они по-прежнему находятся в библиотеке импорта. Это не повлияет на код, который использует функции в статическом режиме. Изменения затронут только код, использующий эти функции динамически.

  • Макросы PROP_ENTRY и PROP_ENTRY_EX устарели и заменены макросами PROP_ENTRY_TYPE_EX и PROP_ENTRY_TYPE по соображениям безопасности.

Общие классы ATL и MFC

  • Невозможно выполнить сборку ATL без зависимости от CRT. В более ранних версиях Visual Studio можно было использовать #define ATL_MIN_CRT, чтобы установить минимальную зависимость проекта ATL от CRT. В Visual Studio 2008 все проекты ATL минимально зависят от CRT независимо от того, определен ли ATL_MIN_CRT.

  • База кода сервера ATL была выпущена в виде проекта с общим исходным кодом в CodePlex и не устанавливается как часть Visual Studio. Классы кодирования и декодирования данных из файла atlenc.h и служебных функций и классы из файлов atlutil.h и atlpath.h сохранились и теперь входят в библиотеку ATL. Некоторые файлы, связанные с сервером ATL, больше не являются частью Visual Studio.

  • Некоторые функции больше не входят в библиотеку DLL. Они по-прежнему находятся в библиотеке импорта. Это не повлияет на код, который использует функции в статическом режиме. Изменения затронут только код, использующий эти функции динамически.

MFC

  • CTime Класс: класс CTime теперь принимает даты начиная с 1.1.1.1900 C.E. вместо 1.1.1.1.1970 C.E.

  • Последовательность табуляций элементов управления в диалоговых окнах MFC: правильная последовательность нескольких элементов управления в диалоговом окне MFC нарушается, если в нее вставляется элемент управления MFC ActiveX. Это изменение устраняет данную проблему.

    Например, создайте диалоговое приложение MFC с элементом управления ActiveX и несколькими элементами управления редактированием. Поместите элемент управления ActiveX в середине последовательности табуляции элементов управления редактирования. Запустите приложение, щелкните элемент управления редактирования, порядок вкладок которого находится после элемента activeX, а затем вкладка. До этого изменения фокус перешел к элементу управления правки после элемента ActiveX вместо следующего элемента управления редактирования в порядке табуляции.

  • CFileDialog Класс. Пользовательские шаблоны для CFileDialog класса не могут быть автоматически перенесены в Windows Vista. Их по-прежнему можно использовать, но у них не будет дополнительной функциональности или вида диалоговых окон в стиле Windows Vista.

  • Класс CWnd и класс CFrameWnd: метод CWnd::GetMenuBarInfo удален.

    Метод CFrameWnd::GetMenuBarInfo теперь является невиртуальным. Дополнительные сведения см. в разделе о функции GetMenuBarInfo в Windows SDK.

  • Поддержка MFC ISAPI: MFC больше не поддерживает создание приложений с помощью интерфейса ISAPI. Чтобы создать приложение ISAPI, вызывайте расширения ISAPI напрямую.

  • Нерекомендуемые API ANSI: не рекомендуется использовать версии ANSI нескольких методов MFC. В будущих приложениях следует использовать версии Юникод этих методов. Дополнительные сведения см. в разделе Требования к сборке для использования стандартных элементов управления в Windows Vista.

Критические изменения в Visual Studio 2005

CRT - библиотека

  • Многие функции теперь являются нерекомендуемыми. См. раздел Нерекомендуемые функции CRT.

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

  • Значение –2 дескриптора файла теперь используется для указания на то, что stdout и stderr недоступны для выходных данных, например в приложении Windows без окна консоли. Ранее использовалось значение -1. Дополнительные сведения см. в разделе _fileno.

  • Были удалены однопоточные библиотеки CRT (libc.lib и libcd.lib). Следует использовать многопоточные библиотеки CRT. Флаг компилятора /ML больше не поддерживается. Незаблокированные версии некоторых функций добавлены для случаев, когда разница в производительности между однопоточным и многопоточным кодом может быть существенной.

  • Перегрузка pow, double pow(int, int) была удалена в целях улучшения соответствия стандарту.

  • Описатель формата %n больше не поддерживается по умолчанию ни в одной из функций семейства printf, так как он изначально небезопасен. При обнаружении описателя %n по умолчанию вызывается обработчик недопустимого параметра. Чтобы включить поддержку %n, используйте _set_printf_count_output (см. также описание _get_printf_count_output).

  • Функция sprintf теперь печатает знак "минус" для нуля со знаком.

  • Функция swprintf изменена для соответствия стандарту, в ней теперь необходимо указывать параметр размера. Форма swprintf без параметра размера не рекомендуется.

  • _set_security_error_handler был удален. Следует удалить все вызовы этой функции; более безопасно работать с ошибками безопасности с помощью обработчика по умолчанию.

  • time_t теперь является 64-разрядным значением (пока не задано _USE_32BIT_TIME_T).

  • При успешном выполнении функции _spawn и _wspawn теперь оставляют значение errno неизмененным согласно стандарту C.

  • RTC теперь по умолчанию использует широкие (многобайтовые) символы.

  • Функции поддержки слов с плавающей запятой не рекомендуются в приложениях, скомпилированных с параметром /CLR или /CLR:PURE. Вот эти функции: _clear87, _clearfp, _control87, _controlfp, _fpreset, _status87, _statusfp. Соответствующее предупреждающее сообщение можно отключить, задав параметр _CRT_MANAGED_FP_NO_DEPRECATE, однако следует иметь в виду, что использование этих функций в управляемом коде непредсказуемо и не поддерживается.

  • Некоторые функции теперь возвращают указатели const. Можно восстановить старое поведение с указателями, не являющимися константами, задав параметр _CONST_RETURN. Вот эти функции:

    • memchr, wmemchr

    • strchr, wcschr, _mbschr, _mbschr_l

    • strpbrk, wcspbrk, _mbspbrk, _mbspbrk_l

    • strrchr, wcsrchr, _mbsrchr, _mbsrchr_l

    • strstr, wcsstr, _mbsstr, _mbsstr_l

  • При связывании с Setargv.obj или Wsetargv.obj больше невозможно запретить развертывание подстановочного знака в командной строке путем заключения его в двойные кавычки. Дополнительные сведения см. в статье Expanding Wildcard Arguments (Расширение аргументов заполнителей).

Стандартная библиотека (2005)

  • Класс исключений (расположенный в заголовке <exception> ) был перемещен в std пространство имен. В предыдущих версиях этот класс находился в глобальном пространстве имен. Чтобы устранить ошибки, указывающие на невозможность найти класс исключения, добавьте в код следующий оператор using: using namespace std;

  • При вызове valarray::resize() содержимое valarray будет утеряно и заменено значениями по умолчанию. Метод resize() предназначен для повторной инициализации valarray, а не для его динамического увеличения, подобно вектору.

  • Итераторы отладки: в приложениях, построенных с помощью отладочной версии библиотеки времени выполнения C и неправильно использующих итераторы, во время выполнения могут появляться утверждения. Чтобы отключить эти утверждения, необходимо определить _HAS_ITERATOR_DEBUGGING (замененные _ITERATOR_DEBUG_LEVEL после Visual Studio 2010) на 0. Дополнительные сведения см. в статье Debug Iterator Support (Поддержка итераторов при отладке).

Критические изменения в Visual C++ .NET 2003

GNU C ++

  • Для определенной директивы препроцессора (C2004) теперь требуется закрывающая скобка.

  • Явные специализации больше не находят параметры шаблона из основного шаблона (Ошибка компилятора C2146).

  • Защищенный член (n) может быть доступен только посредством функции-члена класса (B), который наследует от класса (A), членом которой он (n) является (Ошибка компилятора C2247).

  • Улучшенные проверки доступности проверки в компиляторе теперь обнаруживают недоступные базовые классы (Ошибка компилятора C2248).

  • Исключение не может быть перехвачено, если деструктор или конструктор копий недоступны (C2316).

  • Аргументы по умолчанию в указателях на функции больше не допускаются (Ошибка компилятора C2383).

  • Статические данные-член не могут быть инициализированы в производном классе (Ошибка компилятора C2477).

  • Инициализация не typedef допускается стандартом и теперь создает ошибку компилятора (ошибка компилятора C2513).

  • bool теперь является правильным типом (ошибка компилятора C2632).

  • UDC теперь может приводить к неоднозначности с перегруженными операторами (C2666).

  • Увеличено количество выражений, считающихся допустимыми константами пустого указателя (Ошибка компилятора C2668).

  • теперь требуется шаблон<> в тех местах, где компилятор ранее подразумевал его (ошибка компилятора C2768).

  • Явная специализация функции-члена вне класса является недопустимой, если функция уже была явно задана через специализацию класса шаблона (Ошибка компилятора C2910).

  • Параметры шаблона, не являющегося типом с плавающей запятой, больше не допускаются (Ошибка компилятора C2993).

  • Шаблоны классов недопустимы в качестве аргументов типа шаблона (C3206).

  • Понятные имена функций более не вводятся в содержащее пространство имен (Ошибка компилятора C3767).

  • Компилятор больше не принимает лишние запятые в макросе (C4002).

  • Для объекта типа POD, созданного с помощью инициализатора вида (), будет выполнена инициализация по умолчанию (C4345).

  • typename теперь является обязательным, если зависимое имя обрабатывается как тип (Предупреждение компилятора (уровень 1) C4346).

  • Функции, которые неправильно считались специализациями шаблонов, больше таковыми не считаются (C4347).

  • Статические данные-член не могут быть инициализированы в производном классе (C4356).

  • Специализация шаблона класса должна быть задана до ее использования в типе возвращаемого значения (Предупреждение компилятора (уровень 3) C4686).

  • Теперь компилятор сообщает о недостижимом коде (C4702).

См. также

Новые возможности C++ в Visual Studio