Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье описываются критические изменения, начиная с Visual Studio 2015 и до Visual Studio 2003, а термины "новое поведение" и "теперь" относятся к Visual Studio 2015 и более поздним версиям. Термины "старое поведение" и "раньше" относятся к Visual Studio 2013 и более ранних версий.
Сведения о последней версии Visual Studio см. в статье "Новые возможности для C++ в Visual Studio и C++ по улучшению соответствия в Visual Studio.
Примечание.
Бинарных изменений, нарушающих совместимость, между Visual Studio 2015 и Visual Studio 2017 нет.
При обновлении до новой версии Visual Studio могут возникать ошибки компиляции и ошибки во время выполнения кода, который ранее правильно компилировался и выполнялся. Изменения в новой версии, вызывающие такие проблемы, именуются критическими изменениямии, как правило, связаны с изменениями стандарта языка C++, сигнатур функций или структуры объектов в памяти.
Чтобы избежать ошибок во время выполнения, которые сложно выявить и диагностировать, рекомендуется не создавать статических ссылок на двоичные файлы, скомпилированные с помощью другой версии компилятора. Кроме того, при обновлении проекта EXE или DLL обязательно обновите библиотеки, на которые он ссылается. Не передавайте типы CRT (среда выполнения языка C) или стандартной библиотеки C++ между двоичными файлами (в том числе библиотеками DLL), скомпилированными с помощью разных версий компилятора. Дополнительные сведения см. в разделе Потенциальные ошибки при передаче объектов CRT через границы DLL.
Не создавайте код, зависящий от конкретной структуры, для объекта, который не является интерфейсом 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, vcruntimeversion.dll, и vcruntimedversion.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на версию с плавающей запятой, напримерabsдля двойного аргументаfabsили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_beginthreadи_beginthreadexфункции теперь содержат ссылку на модуль, в котором процедура потока определена на протяжении выполнения потока. Это помогает гарантировать, что модули не будут выгружены до завершения потока.
<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.libgets и _getws
Функции gets и _getws были удалены. Функция gets была удалена из стандартной библиотеки C в C11, так как ее нельзя использовать безопасным образом. Функция _getws была расширением Microsoft, эквивалентным функции gets, но предназначенным для широких строк. В качестве альтернативы этим функциям можно использовать fgets, fgetws, gets_s и _getws_s.
_cgets и _cgetws
Функции _cgets и _cgetws были удалены. В качестве альтернативы этим функциям можно использовать _cgets_s и _cgetws_s.
Форматирование бесконечностей и значений NaN
В предыдущих версиях бесконечности и значения NaN форматировались с использованием набора контрольных строк из 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>, поэтому пользовательский код мог получить доступ к FILE и изменить его внутренности. Библиотека была изменена, чтобы скрыть детали реализации. В рамках этого изменения FILE, как определено в<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 рассматривается как недопустимый параметр. Эта проблема была устранена, но это изменение, нарушающее работу среды выполнения.Функции кучи
Функции
_heapadd,_heapsetи_heapusedбыли удалены. Эти функции перестали работать после обновления CRT для использования динамической памяти Windows.smallheap
Вариант ссылки
smallheapбыл удален. См. раздел Link Options._Стат
Семейство функций
_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функция была реализована с помощью APIGetSystemTimeAsFileTimeWindows. При такой реализации функция 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 namespace std;", и подключаете заголовочный файл стандартной библиотеки C++ (например,<functional>, который включает в себя<tuple>, который теперь объявляетstd::array).steady_clock
<chrono>Реализацияsteady_clockизменилась в соответствии со стандартными требованиями 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++ всегда требует, чтобы n было равно значению, переданному в качестве первого аргумента при вызовеallocate, который возвращает p. Однако в текущей версии значение n проверяется. Код, который передает для n аргументы, отличающиеся от требований стандарта, может завершиться со сбоем во время выполнения.hash_map и hash_set
Файлы заголовков
<hash_map>и<hash_set>, нестандартные и устаревшие в Visual Studio 2015, будут удалены в будущих версиях. Взамен используйте<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_lvalue_reference (добавить ссылку на lvalue) Конструктор по умолчанию (has_default_constructor) доступен для создания по умолчанию имеет_копирующий_конструктор конструируем ли мы копию has_move_constructor is_move_constructible (перемещаемый_конструктор) имеет конструктор без исключений is_nothrow_default_constructible проверка наличия noexcept-конструктора по умолчанию is_nothrow_default_constructible has_nothrow_copy is_nothrow_copy_constructible (проверяет, может ли объект быть скопирован без выброса исключений) has_nothrow_copy_constructor is_nothrow_copy_constructible (проверяет, может ли объект быть скопирован без выброса исключений) имеет_безвыбросный_конструктор_перемещения is_nothrow_move_constructible имеет_гарантию_отсутствия_исключений_при_присваивании Возможность_без_исключения_назначения_копирования has_nothrow_copy_assign Возможность_без_исключения_назначения_копирования имеет_без_исключений_перемещ_опр_назначение is_nothrow_move_assignable имеет тривиальный конструктор is_trivially_default_constructible имеет тривиальный конструктор по умолчанию is_trivially_default_constructible has_trivial_copy (имеется тривиальная копия) is_trivially_copy_constructible имеет тривиальный конструктор перемещения is_trivially_move_constructible (является тривиально перемещаемо конструируемым) имеет_тривиальное_присваивание тривиально_копируемый_присваиваемый has_trivial_move_assign (имеет тривиальное перемещение) is_trivially_move_assignable хас_тривиал_деструктор яввляется_тривиально_разрушаемым Политики launch::any и launch::sync
Нестандартные политики
launch::anyиlaunch::syncбыли удалены. Вместо этого дляlaunch::anyиспользуйтеlaunch:async | launch:deferred. Дляlaunch::syncиспользуйтеlaunch::deferred. См. launch Enumeration.
MFC и ATL
Классы Microsoft Foundation (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
В оператор
deleteбыло внесено изменение для обеспечения соответствия стандарту C++14. Сведения об изменении стандартов можно найти на странице C++ Sized Deallocation. Изменения добавляют форму глобальногоdeleteоператора, который принимает параметр размера. Критическое изменение заключается в том, что если вы ранее использовали операторdeleteс той же сигнатурой (чтобы соответствовать новому оператору размещения), вы получите ошибку компилятора (C2956, которая возникает в точке, где используется новое размещение, так как это позиция в коде, где компилятор пытается определить соответствующий оператор сопоставленияdelete).Функция
void operator delete(void *, size_t)была оператором delete для размещения памяти, соответствующим оператору new для размещения памятиvoid * operator new(size_t, size_t)в C++11. С добавлением функции освобождения памяти размера C++14 эта функция удаления теперь является обычной функцией освобождения памяти (глобальныйdeleteоператор). Согласно стандарту, если использование placement new ищет соответствующую функцию delete и находит обычную функцию освобождения, программа является некорректной.Например, предположим, что код определяет как размещаемый оператор new, так и размещаемый оператор delete:
void * operator new(std::size_t, std::size_t); void operator delete(void*, std::size_t) noexcept;Проблема возникает из-за совпадения сигнатур функций между определенным вами оператором позиционного удаления и новым глобальным оператором с указанием размера. Рассмотрите возможность использования другого типа, отличного от
size_tлюбого placement new и операторовdelete. Типsize_ttypedefкомпиляторо-зависимый; в MSVC этоtypedefunsigned int. Хорошим решением является использование перечисляемого типа, например:enum class my_type : size_t {};Затем измените определение placement new и
delete, чтобы использовать этот тип в качестве второго аргумента вместоsize_t. Кроме того, необходимо обновить вызовы placement new для передачи нового типа (например, используяstatic_cast<my_type>для преобразования из целочисленного значения) и обновить определениеnewиdeleteдля приведения обратно к целочисленному типу. Вам не нужно использоватьenum; также подойдет тип класса с членомsize_t.Альтернативным решением является то, что вы могли бы полностью убрать placement new. Если ваш код использует placement new для реализации пула памяти, где аргумент размещения является размером выделяемого или освобождаемого объекта, то функция размерного освобождения может подойти для замены вашего собственного кода пула памяти, и вы можете избавиться от функции для размещения и просто использовать собственный оператор с двумя аргументами
deleteвместо функции для размещения.Если вы не хотите немедленно обновлять код, можно вернуться к старому поведению с помощью параметра компилятора
/Zc:sizedDealloc-. Если вы используете этот параметр, функции удаления с двумя аргументами не существуют и не создадут конфликта с оператором placement delete.Члены данных объединения
Поля данных объединений теперь не могут иметь ссылочные типы. Следующий код успешно компилируется в 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; }Разрешение шаблонов
В разрешение имен для шаблонов внесены изменения. В 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(){} // OKtypename не допускается в инициализаторе члена
Следующий код теперь вызывает ошибку 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); };Чтобы исправить эту ошибку, добавьте объявление друга для
S2вS: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' labelswarning C4061: enumerator 'bit1' in switch of enum 'flags' is not explicitly handled by a case labelwarning C4062: enumerator 'bit1' in switch of enum 'flags' is not handledwarning 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' labelswarning C4808: case 'value' is not a valid value for switch condition of type 'bool'Warning C4809: switch statement has redundant 'default' label; all possible 'case' labels are givenПример предупреждения C4063 (раньше)
class settings { public: enum flags { bit0 = 0x1, bit1 = 0x2, ... }; ... }; int main() { auto val = settings::bit1; switch (val) { case settings::bit0: break; case settings::bit1: break; case settings::bit0 | settings::bit1: // warning C4063 break; } }Пример C4063 (после)
class settings { ... }; // as above int main() { // since C++11, use std::underlying_type to determine the underlying type of an enum typedef std::underlying_type< settings::flags> ::type flags_t; auto val = settings::bit1; switch (static_cast< flags_t> (val)) { case settings::bit0: break; case settings::bit1: break; case settings::bit0 | settings::bit1: // ok break; } };Примеры других восстановленных предупреждений приведены в соответствующей документации.
#include: использование описателя родительского каталога '.' в имени пути (только влияет)
/Wall/WXВ предыдущих версиях компилятора не определялись случаи использования спецификатора parent-directory ".." в пути директив
#include. Код, написанный таким образом, обычно предназначен для включения заголовков, находящихся за пределами проекта, путем неправильного использования относительных путей к проектам. Это прежнее поведение создавало риск того, что при компиляции программы мог включаться не тот файл исходного кода, который планировал программист, или что эти относительные пути невозможно было бы перенести в другие среды сборки. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет о нем программиста и выдает необязательное предупреждение C4464, если оно включено.warning C4464: relative include path contains '..'Пример (раньше)
#include "..\headers\C4426.h" // emits warning C4464Пример (теперь)
#include "C4426.h" // add absolute path to 'headers\' to your project's include directoriesКроме того, хотя компилятор не выдает соответствующего диагностического сообщения, мы также рекомендуем не использовать описатель родительского каталога ".." для указания включаемых в проект каталогов.
#pragma optimize() расширяет прошлый конец файла заголовка (влияет только на
/Wall/WX)В предыдущих версиях компилятора не обнаруживались изменения в параметрах флагов оптимизации, выходящие за рамки заголовочного файла, включенного в единицу трансляции. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет о нем программиста и выдает необязательное предупреждение C4426 в месте нахождения неправильного
#include, если оно включено. Это предупреждение выдается только в том случае, если изменения конфликтуют с флагами оптимизации, установленными аргументами командной строки, переданными в компилятор.warning C4426: optimization flags changed after including header, may be due to #pragma optimize()Пример (раньше)
// C4426.h #pragma optimize("g", off) ... // C4426.h ends // C4426.cpp #include "C4426.h" // warning C4426Пример (теперь)
// C4426.h #pragma optimize("g", off) ... #pragma optimize("", on) // restores optimization flags set via command-line arguments // C4426.h ends // C4426.cpp #include "C4426.h"Несоответствие #pragma warning(push) и #pragma warning(pop) (влияет только на
/Wall/WX)В предыдущих версиях компилятора не обнаруживалось сопоставление изменений состояния
#pragma warning(push)с изменениями состояния#pragma warning(pop)в другом файле исходного кода, которое редко бывает намеренным. Это прежнее поведение создавало риск того, что программа будет компилироваться с другим набором активных предупреждений, чем тот, который задумывал программист, что могло привести к незаметным искажениям в поведении программы во время выполнения. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет о нем программиста и выдает необязательное предупреждение C5031 в месте нахождения соответствующего#pragma warning(pop), если это предупреждение включено. Это предупреждение включает примечание, ссылающееся на расположение соответствующего #pragma warning(push).warning C5031: #pragma warning(pop): likely mismatch, popping warning state pushed in different fileПример (раньше)
// C5031_part1.h #pragma warning(push) #pragma warning(disable:####) ... // C5031_part1.h ends without #pragma warning(pop) // C5031_part2.h ... #pragma warning(pop) // pops a warning state not pushed in this source file ... // C5031_part1.h ends // C5031.cpp #include "C5031_part1.h" // leaves #pragma warning(push) 'dangling' ... #include "C5031_part2.h" // matches 'dangling' #pragma warning(push), resulting in warning C5031 ...Пример (теперь)
// C5031_part1.h #pragma warning(push) #pragma warning(disable:####) ... #pragma warning(pop) // pops the warning state pushed in this source file // C5031_part1.h ends without #pragma warning(pop) // C5031_part2.h #pragma warning(push) // pushes the warning state pushed in this source file #pragma warning(disable:####) ... #pragma warning(pop) // C5031_part1.h ends // C5031.cpp #include "C5031_part1.h" // #pragma warning state changes are self-contained and independent of other source files or their #include order. ... #include "C5031_part2.h" ...Хотя и редко, иногда код намеренно пишется таким образом. Код, написанный таким образом, чувствителен к изменениям в порядке
#include. Мы рекомендуем, чтобы, по возможности, файлы исходного кода автономно управляли состоянием предупреждений.Несоответствующее #pragma warning(push) (влияет только на
/Wall/WX)В предыдущих версиях компилятора не обнаруживались несоответствия в изменениях состояния
#pragma warning(push)в конце блока трансляции. Компилятор теперь обнаруживает код, написанный таким образом, уведомляет об этом программиста и выдает необязательное предупреждение C5032 в месте несовпадения#pragma warning(push), если это предупреждение включено. Это предупреждение выдается лишь в случае, если в единице трансляции нет ошибок компиляции.warning C5032: detected #pragma warning(push) with no corresponding #pragma warning(pop)Пример (раньше)
// C5032.h #pragma warning(push) #pragma warning(disable:####) ... // C5032.h ends without #pragma warning(pop) // C5032.cpp #include "C5032.h" ... // C5032.cpp ends -- the translation unit is completed without #pragma warning(pop), resulting in warning C5032 on line 1 of C5032.hПример (теперь)
// C5032.h #pragma warning(push) #pragma warning(disable:####) ... #pragma warning(pop) // matches #pragma warning (push) on line 1 // C5032.h ends // C5032.cpp #include "C5032.h" ... // C5032.cpp ends -- the translation unit is completed without unmatched #pragma warning(push)В результате усовершенствования отслеживания состояния #pragma warning могут выдаваться дополнительные предупреждения
В предыдущей версии компилятора изменения состояния #pragma warning отслеживались недостаточно хорошо для того, чтобы выдавались все необходимые предупреждения. В результате возникал риск того, что некоторые предупреждения могли подавляться в ситуациях, не предусмотренных программистом. Теперь компилятор более тщательно отслеживает состояние
#pragma warning, а особенно изменения состояния#pragma warningвнутри шаблонов. При необходимости он также выдает новые предупреждения C5031 и C5032, которые призваны помочь программисту в определении случаев непредусмотренного использования#pragma warning(push)и#pragma warning(pop).В результате усовершенствованного отслеживания изменения состояния
#pragma warningтеперь могут выдаваться предупреждения, которые раньше некорректно подавлялись, или предупреждения о проблемах, которые ранее диагностировались неправильно.Улучшенное определение недостижимого кода
Изменения, внесенные в стандартную библиотеку C++, и улучшенная возможность встраивания вызовов функций по сравнению с предыдущими версиями компилятора позволяют компилятору определять недостижимость определенного кода. Это новое поведение может привести к новым и более часто выдаваемым экземплярам предупреждения C4720.
warning C4720: unreachable codeЗачастую это предупреждение выдается только при компиляции с включенными оптимизациями, так как при этом может встраиваться больше вызовов функций, удаляться избыточный код или могут производиться другие действия, позволяющие определить недостижимость определенного кода. По нашим наблюдениям, предупреждение C4720 начало часто появляться в блоках try/catch, особенно в связи с использованием std::find.
Пример (раньше)
try { auto iter = std::find(v.begin(), v.end(), 5); } catch (...) { do_something(); // ok }Пример (теперь)
try { auto iter = std::find(v.begin(), v.end(), 5); } catch (...) { do_something(); // warning C4702: unreachable code }
Улучшения соответствия в обновлении 2
В результате частичной поддержки правила SFINAE для выражений могут возникать дополнительные предупреждения и ошибки
В предыдущих версиях компилятора из-за отсутствия поддержки правила SFINAE для выражений не анализировались некоторые типы выражений внутри описателей
decltype. Это поведение было неправильным и не соответствовало стандарту языка C++. В результате непрерывной оптимизации соответствия компилятор теперь анализирует эти выражения и частично поддерживает правило SFINAE для выражений. Поэтому компилятор теперь выдает предупреждения и сообщения об ошибках, найденных в выражениях, которые в предыдущих версиях компилятора не анализировались.Когда это новое поведение анализирует
decltypeвыражение, которое включает тип, который еще не объявлен, компилятор выдает ошибку компилятора C2039 в результате.error C2039: 'type': is not a member of 'global namespace'Пример 1. Использование необъявленного типа (ранее)
struct s1 { template < typename T> auto f() - > decltype(s2< T> ::type::f()); // error C2039 template< typename> struct s2 {}; }Пример 1 после изменений
struct s1 { template < typename> // forward declare s2struct s2; template < typename T> auto f() - > decltype(s2< T> ::type::f()); template< typename> struct s2 {}; }Когда это новое поведение анализирует
decltypeвыражение, в котором отсутствует необходимое использование ключевого словаtypename, чтобы указать, что зависимое имя является типом, компилятор выдает предупреждение компилятора C4346 и ошибку компилятора C2923.warning C4346: 'S2<T>::Type': dependent name is not a typeerror 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 allowederror 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_convertible теперь обнаруживает самоприсваивание (стандартная библиотека)
Предыдущие версии признака типа
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). Компилятор больше не принимает код, написанный таким образом. Теперь компилятор выдает предупреждение CC4599, чтобы помочь выявить несоответствующие аргументы командной строки директории для включаемых файлов (-I) при использовании PCH-файлов.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
Компилятор
Ключевое слово 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 "тип" для уменьшенного отношения (то есть тот же тип, если оно уже уменьшено).При вызове
std::min()илиstd::max()необходимо использовать#include <algorithm>.Если в вашем существующем коде используются симулированные перечисления с областью видимости из предыдущей версии — традиционные неограниченные перечисления, упакованные в пространства имен, это необходимо изменить. Например, если вы ссылались на тип
std::future_status::future_status, теперь вы должны использоватьstd::future_status. Однако на большую часть кода это не влияет, напримерstd::future_status::readyпо-прежнему компилируется.explicit operator bool()более строгий, чем оператор 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, вы можете скачать ее из Центра загрузок Майкрософт в Multibyte MFC Library for 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изменилась на (CWnd*, HANDLE) вместо (WPARAM, LPARAM), чтобы использовать новый макрос ON_WM_DDE_EXECUTE в карте сообщений.Функция
CFrameWnd::OnDDETerminateизменилась на (CWnd*) в качестве параметра вместо (WPARAM, LPARAM), чтобы новый макрос 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 больше не завиcит от набора символов или кода, специфичного для отладки/выпуска. Поскольку она работает одинаково для Юникода/ANSI и отладки/выпуска, достаточно одной версии библиотеки.
Средство трассировки ATL/MFC удалено вместе с ATL DLL, а механизм трассировки стал проще. Конструктор
CTraceCategoryтеперь принимает один параметр (имя категории), а макросы TRACE вызывают функции отчетов отладки CRT.
Критические изменения в Visual Studio 2012
Компилятор
Параметр компилятора
/Ylбыл изменен. По умолчанию компилятор использует этот параметр, который при определенных условиях может привести к ошибкам LNK2011. Дополнительные сведения см. в статье /Yl (Inject PCH Reference for Debug Library) (Параметр /Yl (вставка ссылки на PCH-файл для библиотеки отладки) (C++)).В коде, который компилируется с помощью
/clr, ключевое слово классаenumопределяет перечисление C++11, а не общее перечисление языка выполнения (CLR). Чтобы определить перечисление CLR, необходимо явно указать его доступность.Используйте ключевое слово template для явного разрешения зависимого имени (соответствие стандарту C++). В следующем примере ключевое слово выделенного шаблона необходимо, чтобы устранить неоднозначность. Дополнительные сведения см. в разделе Разрешение имен для зависимых типов.
template < typename X = "", typename = "" AY = ""> struct Container { typedef typename AY::template Rebind< X> ::Other AX; };Константное выражение типа float больше не поддерживается как аргумент шаблона, как показано в следующем примере.
template<float n=3.14> struct B {}; // error C2993: 'float': illegal type for non-type template parameter 'n'Код, который компилируется с помощью параметра командной строки
/GSи имеет одну уязвимость, может привести к завершению процесса во время выполнения, как показано в следующем примере псевдокода.char buf[MAX]; int cch; ManipulateString(buf, &cch); // ... buf[cch] = '\0'; // if cch >= MAX, process will terminateПо умолчанию архитектура сборки x86 изменена на SSE2. Таким образом, компилятор может создавать инструкции SSE и будет использовать регистры XMM для выполнения вычислений с плавающей запятой. Если вы хотите вернуться к предыдущему поведению, используйте флаг компилятора
/arch:IA32для указания архитектуры как IA32.Компилятор может выдавать предупреждения Предупреждение компилятора (уровень 4) C4703 и C4701 в тех случаях, где ранее этого не делал. Компилятор применяет более строгие проверки для использования неинициализированных локальных переменных типа указателя.
Когда установлен новый флаг компоновщика
/HIGHENTROPYVA, Windows 8 обычно при выделении памяти возвращает 64-разрядный адрес. (До Windows 8 такие выделения чаще возвращали адреса, которые были менее 2 ГБ.) Это изменение может вскрывать ошибки усечения указателя в имеющемся коде. По умолчанию этот параметр включен. Значение/HIGHENTROPYVA:NOотключает это поведение.Управляемый компилятор (Visual Basic или C#) также поддерживает
/HIGHENTROPYVAдля управляемых сборок. Однако в этом случае параметр/HIGHENTROPYVAswitchотключен по умолчанию.
Интегрированная среда разработки (IDE)
- Хотя рекомендуется не создавать приложения Windows Forms в C++/CLI, поддерживается обслуживание существующих приложений пользовательского интерфейса C++/CLI. Если необходимо создать приложение Windows Forms или любое другое приложение пользовательского интерфейса .NET, используйте C# или Visual Basic. Используйте C++/CLI только в целях взаимодействия.
Библиотека параллельных шаблонов и библиотека среды выполнения с параллелизмом
Перечисление SchedulerTypeUmsThreadDefault является устаревшим. Спецификация UmsThreadDefault выдает предупреждение о нерекомендуемом использовании и внутренне сопоставляется с ThreadScheduler.
Стандартная библиотека
После критических изменений между стандартами C++98/03 и C++11 код, использующий явное указание шаблонных аргументов для вызова
make_pair(), как, например, вmake_pair<int, int>(x, y), обычно не компилируется в Visual C++ в Visual Studio 2012. Решение заключается в том, чтобы всегда вызыватьmake_pair()без явных аргументов шаблона , как и вmake_pair(x, y). Предоставление явно заданных аргументов шаблона уничтожает назначение функции. Если требуется точный контроль над результирующим типом, используйтеpairвместоmake_pair— как вpair<short, short>(int1, int2).Еще одно критическое изменение между стандартами C++98/03 и C++11: если A неявно преобразуется в B и B неявно преобразуется в C, но A неявно не преобразуется в C, C++98/03 и Visual Studio 2010 разрешено
pair<A, X>преобразовать (неявно или явно) вpair<C, X>. (Другой тип, X, не представляет интереса здесь и не относится конкретно к первому типу в паре.) Компилятор C++ в Visual Studio 2012 обнаруживает, что A не может неявно преобразовываться в C, поэтому удаляет преобразование пары из разрешения перегрузки. Это изменение является положительным во многих ситуациях. Например, благодаря этому изменению перегрузкаfunc(const pair<int, int>&)иfunc(const pair<string, string>&), а также вызовfunc()сpair<const char *, const char *>успешно компилируются. Однако это изменение нарушает код, основанный на агрессивных преобразованиях пар. Такой код обычно может быть исправлен выполнением одной из частей преобразования явно, например путем передачиmake_pair(static_cast<B>(a), x)в функцию, ожидающуюpair<C, X>.Visual Studio 2010 имитировал вариативные шаблоны (шаблоны с переменным числом аргументов), например
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(и связанная процедура таймера). Вместо него используйте 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:CFrameWndExCMDIFrameWndExCPaneFrameWnd
Изменены имя и сигнатура метода
OnDWMCompositionChangedдля соответствия макросу ON_WM_DWMCOMPOSITIONCHANGED:CFrameWndExCMDIFrameWndExCPaneFrameWnd
Изменена сигнатура метода
OnMouseLeaveдля соответствия макросу ON_WM_MOUSELEAVE:CMFCCaptionBarCMFCColorBarCMFCHeaderCtrlCMFCProperySheetListBoxCMFCRibbonBarCMFCRibbonPanelMenuBarCMFCRibbonRichEditCtrlCMFCSpinButtonCtrlCMFCToolBarЗаменитьЭтотТекстCMFCToolBarComboBoxEditCMFCToolBarEditCtrlCMFCAutoHideBar
Изменена сигнатура
OnPowerBroadcastдля соответствия макросу ON_WM_POWERBROADCAST:CFrameWndExCMDIFrameWndEx
Изменена сигнатура
OnStyleChangedдля соответствия макросу ON_WM_STYLECHANGED:CMFCListCtrlCMFCStatusBar
Внутренний метод
FontFamalyProcFontsпереименован вFontFamilyProcFonts.Удалены многочисленные глобальные статические объекты
CStringво избежание утечки памяти в некоторых ситуациях (заменены на #defines) и следующие переменные-члены класса:CKeyBoardManager::m_strDelimiterCMFCPropertyGridProperty::m_strFormatCharCMFCPropertyGridProperty::m_strFormatShortCMFCPropertyGridProperty::m_strFormatLongCMFCPropertyGridProperty::m_strFormatUShortCMFCPropertyGridProperty::m_strFormatULongCMFCPropertyGridProperty::m_strFormatFloatCMFCPropertyGridProperty::m_strFormatDoubleCMFCToolBarImages::m_strPngResTypeCMFCPropertyGridProperty::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:
GetDirectD2dFactoryGetWriteFactoryGetWICFactoryInitD2DReleaseD2DRefsIsD2DInitializedD2D1MakeRotateMatrixНапример, вместо вызова
afxGlobalData.IsD2DInitializedвызовитеAfxGetD2DState->IsD2DInitialized.
Удалены устаревшие файлы ATL*.CPP из папки \atlmfc\include\.
Инициализация
afxGlobalDataвыполняется по запросу, а не во время инициализации CRT, чтобы удовлетворить требованиямDLLMain.Добавлен метод
RemoveButtonByIndexв классCMFCOutlookBarPane.CMFCCmdUsageCount::IsFreqeuntlyUsedCmdисправлено наIsFrequentlyUsedCmd.Исправлено несколько раз, где
RestoreOriginalstateменялось наRestoreOriginalState (CMFCToolBar, CMFCMenuBar, CMFCOutlookBarPane).Удалены неиспользуемые методы из
CDockablePane:SetCaptionStyle,IsDrawCaption,IsHideDisabledButtons,GetRecentSiblingPaneInfoиCanAdjustLayout.Удалены статические переменные-члены
CDockablePanem_bCaptionTextиm_bHideDisabledButtons.Добавлен метод переопределения
DeleteStringвCMFCFontComboBox.Удалены неиспользуемые методы из
CPane:GetMinLengthиIsLastPaneOnLastRow.CPane::GetDockSiteRow(CDockingPanesRow *)переименован вCPane::SetDockSiteRow.
Критические изменения в Visual Studio 2010
Компилятор
Ключевое
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 (Dr. Watson) или отладчик 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. Однако на платформе IA64 по-прежнему существует поддержка CRT и ATL.
В файлах определения модулей (.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
Компилятор
Платформы Windows 95, Windows 98, Windows ME и Windows NT больше не поддерживаются. Эти операционные системы были удалены из списка целевых платформ.
Компилятор больше не поддерживает некоторые атрибутов, которые были непосредственно связаны с сервером ATL. Следующие атрибуты больше не поддерживаются:
счетчик производительности
perf_object
перфмон
обработчик запросов
обработчик SOAP
соап_хэдер
метод_soap
имя_тега
Проекты 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.Библиотеки времени выполнения 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. Они по-прежнему находятся в библиотеке импорта. Это не повлияет на код, который использует функции в статическом режиме. Изменения затронут только код, использующий эти функции динамически.
MФЦ
CTimeКласс: классCTimeтеперь принимает даты начиная с 1.1.1.1900 C.E. вместо 1.1.1.1.1970 C.E.Последовательность табуляций элементов управления в диалоговых окнах MFC: правильная последовательность нескольких элементов управления в диалоговом окне MFC нарушается, если в нее вставляется элемент управления MFC ActiveX. Это изменение устраняет данную проблему.
Например, создайте диалоговое приложение MFC с элементом управления ActiveX и несколькими элементами управления редактированием. Поместите элемент управления ActiveX в середину последовательности табуляции элементов редактирования. Запустите приложение, щелкните поле редактирования, порядок табуляции которого идет после элемента ActiveX, затем нажмите Tab. До этого изменения фокус переходил к полю редактирования, следующему за элементом 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
Компилятор
Для определенной директивы препроцессора (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).