Журнал изменений 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.lib
версия vcruntime.dll,libvcruntimed.lib
и версия vcruntimed.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 определяется встроенным образом.
Определения всех
printf
scanf
функций были перемещены в встроенные<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
функция была реализована с помощью APIGetSystemTimeAsFileTime
Windows. При такой реализации функция clock зависела от системного времени и поэтому не была обязательно монотонной. Функция часов была повторно завершена с точки зренияQueryPerformanceCounter
и теперь монотонна.fstat и _utime
В предыдущих версиях функции
_stat
fstat
и_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 Studiosteady_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_t
typedef
от компилятора; он предназначен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 предупреждения (push) и #pragma предупреждения(pop) (влияет только на
/WX
/Wall
)В предыдущих версиях компилятора не обнаруживалось сопоставление изменений состояния
#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 предупреждения(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) и несоответственное включение каталогов (влияет только на
/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 2013E1
в выражении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()
.Если существующий код использует смоделированные перечисления предыдущего выпуска — традиционные неуправляемые перечисления, упакованные в пространства имен, необходимо изменить его. Например, если вы ссылались на тип
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 MBCS не включена в Visual Studio, так как Юникод настолько популярен и использование MBCS значительно снизилось. Это изменение также обеспечивает более точное соответствие MFC самому Windows SDK, поскольку многие из новых элементов управления и сообщений поддерживают только Юникод. Однако если вы должны продолжать использовать библиотеку MFC MBCS, ее можно скачать из Центра загрузки Майкрософт в библиотеке Многобайтовых 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 только в целях взаимодействия.
Библиотека параллельных шаблонов и библиотека среды выполнения с параллелизмом
Перечисление SchedulerType
UmsThreadDefault
является устаревшим. Спецификация 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 Win32TrackMouseEvent
.Добавлен параметр в конструктор
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
ReplaceThisTextCMFCToolBarComboBoxEdit
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
.Удалены статические переменные-члены
CDockablePane
m_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).