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

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

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

Примечание.

Бинарных изменений, нарушающих совместимость, между Visual Studio 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.lib
    
  • gets и _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 функция была реализована с помощью API GetSystemTimeAsFileTimeWindows. При такой реализации функция 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 Studio steady_clock::time_point теперь является определением типа для chrono::time_point<steady_clock>, однако в других реализациях это может быть не так.

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

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

    bool operator==(const MyAlloc& other)
    

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

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

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

  • std::allocator::deallocate

    В Visual Studio 2013 и более ранних версиях std::allocator::deallocate(p, n) игнорировал аргумент, переданный для n. Стандарт C++ всегда требует, чтобы 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(){} // OK
    
  • typename не допускается в инициализаторе члена

    Следующий код теперь вызывает ошибку C2059.

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

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

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

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

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

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

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

    Чтобы решить эту проблему, оберните значение в struct.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • alignof — ключевое слово

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

    class alignof{}
    
  • constexpr — ключевое слово

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

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

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

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

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

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

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

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

    Следующий код в Visual Studio 2015 вызывает ошибку C2664.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Чтобы исправить эту ошибку, добавьте объявление друга для 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' labels
    
    warning C4061: enumerator 'bit1' in switch of enum 'flags' is not explicitly handled by a case label
    
    warning C4062: enumerator 'bit1' in switch of enum 'flags' is not handled
    
    warning C4063: case 'bit32' is not a valid value for switch of enum 'flags'
    
    warning C4064: switch of incomplete enum 'flags'
    
    warning C4065: switch statement contains 'default' but no 'case' labels
    
    warning C4808: case 'value' is not a valid value for switch condition of type 'bool'
    
    Warning C4809: switch statement has redundant 'default' label; all possible 'case' labels are given
    

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

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

    Пример C4063 (после)

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

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

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

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

    warning C4464: relative include path contains '..'
    

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    warning C4720: unreachable code
    

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

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

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

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

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

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

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

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

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

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

    Пример 1. Использование необъявленного типа (ранее)

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

    Пример 1 после изменений

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

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

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

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

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

    Пример 2 (после)

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

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

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

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

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

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

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

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

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

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

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

    Пример (после)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • std::is_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 2013 E1 в выражении E1::b соответствует определению typedef E2 в main() и имеет тип ::E2.

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

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

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

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

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

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

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

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

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

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

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

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

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

  • При вызове 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 Win32 TrackMouseEvent.

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

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

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

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

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

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

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

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

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

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

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

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

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

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

    • CMFCCaptionBar

    • CMFCColorBar

    • CMFCHeaderCtrl

    • CMFCProperySheetListBox

    • CMFCRibbonBar

    • CMFCRibbonPanelMenuBar

    • CMFCRibbonRichEditCtrl

    • CMFCSpinButtonCtrl

    • CMFCToolBar ЗаменитьЭтотТекст

    • CMFCToolBarComboBoxEdit

    • CMFCToolBarEditCtrl

    • CMFCAutoHideBar

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

    • CFrameWndEx

    • CMDIFrameWndEx

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

    • CMFCListCtrl

    • CMFCStatusBar

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

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

    • CKeyBoardManager::m_strDelimiter

    • CMFCPropertyGridProperty::m_strFormatChar

    • CMFCPropertyGridProperty::m_strFormatShort

    • CMFCPropertyGridProperty::m_strFormatLong

    • CMFCPropertyGridProperty::m_strFormatUShort

    • CMFCPropertyGridProperty::m_strFormatULong

    • CMFCPropertyGridProperty::m_strFormatFloat

    • CMFCPropertyGridProperty::m_strFormatDouble

    • CMFCToolBarImages::m_strPngResType

    • CMFCPropertyGridProperty::m_strFormat

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

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

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

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

    • GetDirectD2dFactory

    • GetWriteFactory

    • GetWICFactory

    • InitD2D

    • ReleaseD2DRefs

    • IsD2DInitialized

    • D2D1MakeRotateMatrix

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

  • Удалены устаревшие файлы 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).

См. также

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