Udostępnij za pośrednictwem


Historia zmian języka Microsoft C/C++ 2003 – 2015

W tym artykule opisano wszystkie zmiany powodujące niezgodność z programu Visual Studio 2015 z powrotem do programu Visual Studio 2003, a w tym artykule terminy "nowe zachowanie" lub "teraz" odnoszą się do programu Visual Studio 2015 i nowszych. Terminy "stare zachowanie" i "przed" odnoszą się do programu Visual Studio 2013 i wcześniejszych wersji.

Aby uzyskać informacje o najnowszej wersji programu Visual Studio, zobacz Co nowego dla języka C++ w programie Visual Studio i ulepszeniach zgodności języka C++ w programie Visual Studio.

Uwaga

W programie Visual Studio 2015 i Visual Studio 2017 nie występują żadne zmiany powodujące niezgodność binarne.

Podczas uaktualniania do nowej wersji programu Visual Studio mogą wystąpić błędy kompilacji i/lub środowiska uruchomieniowego w kodzie, który został wcześniej skompilowany i uruchomiony poprawnie. Zmiany w nowej wersji, które powodują takie problemy, są znane jako zmiany powodujące niezgodność i zazwyczaj są wymagane przez modyfikacje w standardzie języka C++, sygnaturach funkcji lub układzie obiektów w pamięci.

Aby uniknąć błędów czasu wykonywania, które są trudne do wykrycia i zdiagnozowania, zalecamy, aby nigdy nie łączyć się statycznie z plikami binarnymi skompilowanymi przy użyciu innej wersji kompilatora. Ponadto, gdy uaktualniasz projekt EXE lub DLL, upewnij się, że uaktualniasz również biblioteki, z którymi się on łączy. Nie przekazuj typów biblioteki CRT (C Runtime) ani C++ Standard Library (C++ Standard Library) między plikami binarnymi, w tym bibliotekami DLL, skompilowanymi przy użyciu różnych wersji kompilatora. Aby uzyskać więcej informacji, zobacz Potencjalne błędy przekazywania obiektów CRT przez granice bibliotek DLL.

Nigdy nie należy pisać kodu, który zależy od określonego układu obiektu, który nie jest interfejsem COM ani obiektem ZASOB. Jeśli jednak piszesz taki kod, upewnij się, że działa po uaktualnieniu. Aby uzyskać więcej informacji, zobacz Przenośność w granicach ABI.

Ponadto ciągłe ulepszenia zgodności kompilatora mogą czasami zmieniać sposób, w jaki kompilator rozumie istniejący kod źródłowy. Na przykład możesz znaleźć nowe lub różne błędy podczas kompilacji, a nawet różnice behawioralne w kodzie, który został wcześniej skompilowany i wydawał się działać poprawnie. Chociaż te ulepszenia nie są zmianami powodującymi niezgodność, takimi jak te omówione w tym dokumencie, może być konieczne wprowadzenie zmian w kodzie źródłowym, aby rozwiązać następujące problemy:

Zmiany zgodności programu Visual Studio 2015

Biblioteka środowiska uruchomieniowego języka C (CRT)

Zmiany ogólne

  • Refaktoryzowane pliki binarne

    Biblioteka CRT została refaktoryzowana w dwóch różnych plikach binarnych: universal CRT (ucrtbase), która zawiera większość standardowych funkcji i bibliotekę środowiska uruchomieniowego VC (vcruntime). Biblioteka vcruntime zawiera funkcje związane z kompilatorem, takie jak obsługa wyjątków i funkcje wewnętrzne. Jeśli używasz domyślnych ustawień projektu, ta zmiana nie ma wpływu na Ciebie, ponieważ konsolidator automatycznie używa nowych bibliotek domyślnych. Jeśli właściwość konsolidatora projektu ignoruj wszystkie biblioteki domyślne na Wartość Tak lub używasz /NODEFAULTLIB opcji konsolidatora w wierszu polecenia, musisz zaktualizować listę bibliotek (we właściwości Dodatkowe zależności), aby uwzględnić nowe, refaktoryzowane biblioteki. Zastąp starą bibliotekę CRT (libcmt.lib, libcmtd.lib, msvcrt.lib, msvcrtd.lib) równoważną refaktoryzowaną biblioteką. Dla każdej z dwóch refaktoryzowanych bibliotek istnieją wersje statyczne (lib) i dynamiczne (.dll) oraz wersje wydania (bez sufiksu) i debugowania (z sufiksem "d"). Wersje dynamiczne mają bibliotekę importu, z którą łączysz. Dwie refaktoryzowane biblioteki to Universal CRT, w szczególności ucrtbase.dll lub ucrtbase.lib, ucrtbased.dll lub ucrtbased.lib oraz biblioteka środowiska uruchomieniowego VC, libvcruntime.libwersja vcruntime.dll, libvcruntimed.libi wersja vcruntimed.dll. Wersja programu Visual Studio 2015 i Visual Studio 2017 to 140. Zobacz Funkcje biblioteki CRT.

<locale.h>

  • localeconv

    Funkcja localeconv zadeklarowana w pliku locale.h działa teraz poprawnie po włączeniu ustawień regionalnych dla każdego wątku. W poprzednich wersjach biblioteki ta funkcja zwróci lconv dane dla globalnych ustawień regionalnych, a nie ustawień regionalnych wątku.

    Jeśli używasz ustawień regionalnych dla każdego wątku localeconv, należy sprawdzić użycie elementu . Jeśli w kodzie przyjęto założenie, że lconv zwrócone dane są przeznaczone dla globalnych ustawień regionalnych, należy je poprawić.

<math.h>

  • Przeciążenia biblioteki matematycznej w języku C++

    W poprzednich wersjach <math.h> zdefiniowano niektóre, ale nie wszystkie przeciążenia języka C++ dla funkcji biblioteki matematycznej. Pozostałe przeciążenia znajdowały się w nagłówku <cmath> . Kod, który został uwzględniony <math.h> , może mieć problemy z rozpoznawaniem przeciążenia funkcji. Teraz przeciążenia języka C++ zostały usunięte z <math.h> elementu i znajdują się tylko w pliku <cmath>.

    Aby usunąć błędy, uwzględnij <cmath> deklaracje funkcji, które zostały usunięte z <math.h>programu . Te funkcje zostały przeniesione:

    • double abs(double) i 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)
    • floati wersje funkcji zmiennoprzecinkowych , , atanhasinlog1pasinhlog2atanlrintatan2lroundcbrtmodfceilnearbyintcopysignnextaftercosnexttowardcoshremaindererfremquoerfcrintexptgammafabstansqrtsinhsinscalbnscalblnroundlog10logllroundllrintfrexpfmodfminhypotfmailogbfloortanhexpm1ldexpacoshexp2lgammafmaxfdimi acoslong doubletrunc

    Jeśli masz kod używający abs typu zmiennoprzecinkowego, który zawiera <math.h> tylko nagłówek, wersje zmiennoprzecinkowe nie będą już dostępne. Wywołanie jest teraz rozpoznawane jako abs(int), nawet w przypadku argumentu zmiennoprzecinkowego, co powoduje błąd:

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

    Poprawka tego ostrzeżenia polega na zastąpieniu wywołania abs zmiennoprzecinkowym wersją abselementu , taką jak fabs argument podwójny lub fabsf argument zmiennoprzecinkowy, albo dołączenie <cmath> nagłówka i kontynuowanie używania elementu abs.

  • Zgodność zmiennoprzecinkowa

    Wprowadzono wiele zmian w bibliotece matematycznej w celu poprawy zgodności ze specyfikacjami IEEE-754 i C11 Załącznik F w odniesieniu do specjalnych danych wejściowych przypadków, takich jak NaN i niedociągnienia. Na przykład ciche dane wejściowe NaN, które były często traktowane jako błędy w poprzednich wersjach biblioteki, nie są już traktowane jako błędy. Zobacz IEEE 754 Standard i Załącznik F standardu C11.

    Te zmiany nie spowodują błędów czasu kompilacji, ale mogą spowodować, że programy zachowują się inaczej i bardziej poprawnie zgodnie ze standardem.

  • FLT_ROUNDS

    W programie Visual Studio 2013 makro FLT_ROUNDS zostało rozwinięte do wyrażenia stałego, co było nieprawidłowe, ponieważ tryb zaokrąglania można konfigurować w czasie wykonywania, na przykład przez wywołanie metody fesetround. Makro FLT_ROUNDS jest teraz dynamiczne i poprawnie odzwierciedla bieżący tryb zaokrąglania.

<new> i <new.h>

  • new i delete

    W poprzednich wersjach biblioteki operator zdefiniowany przez implementację nowe i usunięte funkcje zostały wyeksportowane z biblioteki DLL biblioteki środowiska uruchomieniowego (na przykład msvcr120.dll). Te funkcje operatora są teraz zawsze statycznie połączone z plikami binarnymi, nawet w przypadku korzystania z biblioteki DLL biblioteki środowiska uruchomieniowego.

    Nie jest to zmiana powodująca niezgodność dla natywnego lub mieszanego kodu (/clr), jednak w przypadku kodu skompilowanego jako /clr:pure ta zmiana może spowodować niepowodzenie kompilacji kodu. Jeśli skompilujesz kod jako /clr:pure, może być konieczne dodanie #include <new> lub #include <new.h> obejście błędów kompilacji z powodu tej zmiany. Opcja/clr:pure jest przestarzała w programie Visual Studio 2015 i nieobsługiwana w programie Visual Studio 2017. Kod, który musi być "czysty", powinien zostać przekierowany do języka C#.

<process.h>

  • _beginthread i _beginthreadex

    Funkcje _beginthread i _beginthreadex przechowują teraz odwołanie do modułu, w którym procedura wątku jest definiowana przez czas trwania wątku. Pomaga to zapewnić, że moduły nie są zwalniane, dopóki wątek nie zostanie uruchomiony do ukończenia.

<stdarg.h>

  • va_start typy referencyjne i

    Podczas kompilowania kodu C++ sprawdza teraz poprawność w czasie kompilacji, va_start że argument przekazany do niego nie jest typu odwołania. Argumenty typu odwołania są zabronione przez standard C++.

<stdio.h> i <conio.h>

  • Rodzina funkcji printf i scanf jest teraz definiowana w tekście.

    Definicje wszystkich printf funkcji i scanf zostały przeniesione w tekście do <stdio.h>nagłówków , <conio.h>i innych nagłówków CRT. Ta zmiana powodująca niezgodność prowadzi do błędu konsolidatora (LNK2019, nierozwiązanego symbolu zewnętrznego) dla wszystkich programów, które zadeklarowały te funkcje lokalnie bez uwzględniania odpowiednich nagłówków CRT. Jeśli to możliwe, należy zaktualizować kod tak, aby zawierał nagłówki CRT (czyli dodać #include <stdio.h>) i funkcje wbudowane, ale jeśli nie chcesz modyfikować kodu w celu uwzględnienia tych plików nagłówków, alternatywnym rozwiązaniem jest dodanie legacy_stdio_definitions.lib do danych wejściowych konsolidatora.

    Aby dodać tę bibliotekę do danych wejściowych konsolidatora w środowisku IDE, otwórz menu kontekstowe dla węzła projektu, wybierz pozycję Właściwości, a następnie w oknie dialogowym Właściwości projektu wybierz pozycję Konsolidator i edytuj dane wejściowe konsolidatora, aby dodać legacy_stdio_definitions.lib je do listy rozdzielanej średnikami.

    Jeśli projekt łączy się z bibliotekami statycznymi skompilowanymi w wersji programu Visual Studio wcześniej niż 2015, konsolidator może zgłosić nierozwiązany symbol zewnętrzny. Te błędy mogą odwoływać się do wewnętrznych definicji , _iob_iob_funclub powiązanych importów dla niektórych <stdio.h> funkcji w postaci imp*. Firma Microsoft zaleca ponowne kompilowanie wszystkich bibliotek statycznych przy użyciu najnowszej wersji kompilatora i bibliotek języka C++ podczas uaktualniania projektu. Jeśli biblioteka jest biblioteką innej firmy, dla której źródło jest niedostępne, należy zażądać zaktualizowanego pliku binarnego od innej firmy lub hermetyzować użycie tej biblioteki w oddzielnej bibliotece DLL kompilowanej ze starszą wersją kompilatora i bibliotek.

    Ostrzeżenie

    Jeśli łączysz się z zestawem Windows SDK 8.1 lub starszym, mogą wystąpić te nierozwiązane błędy symboli zewnętrznych. W takim przypadku należy rozwiązać ten błąd, dodając plik legacy_stdio_definitions.lib do danych wejściowych konsolidatora zgodnie z wcześniejszym opisem.

    Aby rozwiązać problemy z nierozwiązanym błędami symboli, możesz spróbować użyć polecenia dumpbin.exe , aby sprawdzić symbole zdefiniowane w pliku binarnym. Wypróbuj następujący wiersz polecenia, aby wyświetlić symbole zdefiniowane w bibliotece.

    dumpbin.exe /LINKERMEMBER somelibrary.lib
    
  • pobiera i _getws

    Funkcje pobierania i _getws zostały usunięte. Funkcja gets została usunięta z standardowej biblioteki języka C w języku C11, ponieważ nie można jej bezpiecznie używać. Funkcja _getws była rozszerzeniem firmy Microsoft, które było równoważne pobieraniu, ale dla szerokich ciągów. Jako alternatywy dla tych funkcji należy rozważyć użycie fgets, fgetws, gets_s i _getws_s.

  • _cgets i _cgetws

    Funkcje _cgets i _cgetws zostały usunięte. Jako alternatywy dla tych funkcji należy rozważyć użycie _cgets_s i _cgetws_s.

  • Formatowanie nieskończoności i sieci NaN

    W poprzednich wersjach wartości infinities i NaNs będą formatowane przy użyciu zestawu ciągów sentynel specyficznych dla MSVC.

    • Nieskończoność: 1.#INF

    • Quiet NaN: 1.#QNAN

    • Sygnał NaN: 1.#SNAN

    • NaN nieokreślony: 1.#IND

    Każdy z tych formatów mógł być poprzedzony znakiem i mógł być sformatowany nieco inaczej w zależności od szerokości i dokładności pola (czasami z nietypowymi efektami, na przykład printf("%.2f\n", INFINITY) wydrukowałby 1,#J, ponieważ #INF będzie "zaokrąglany" do 2-cyfrowej precyzji). C99 wprowadził nowe wymagania dotyczące formatowania wartości infiniacji i sieci NaN. Implementacja MSVC jest teraz zgodna z tymi wymaganiami. Nowe ciągi są następujące:

    • Nieskończoność: inf

    • Quiet NaN: nan

    • Signaling NaN: nan(snan)

    • NaN nieokreślony: nan(ind)

    Każdy z nich może być poprzedzony znakiem. Jeśli jest używany specyfikator formatu wielkich liter (%F zamiast %f), ciągi są drukowane wielkimi literami (INF zamiast ), zgodnie z infwymaganiami.

    Funkcje scanf zostały zmodyfikowane, aby przeanalizować te nowe ciągi, więc te ciągi są teraz przekazywane w obie strony printf i scanf.

  • Formatowanie zmiennoprzecinkowe i analizowanie

    Wprowadzono nowe algorytmy formatowania zmiennoprzecinkowego i analizowania w celu poprawy poprawności. Ta zmiana wpływa na rodziny funkcji printf i scanf oraz funkcje takie jak strtod.

    Stare algorytmy formatowania będą generować tylko ograniczoną liczbę cyfr, a następnie wypełnić pozostałe miejsca dziesiętne z zera. Zazwyczaj mogą one generować ciągi, które byłyby zaokrąglone z powrotem do oryginalnej wartości zmiennoprzecinkowej, ale nie były doskonałe, jeśli potrzebujesz dokładnej wartości (lub najbliższej reprezentacji dziesiętnej). Nowe algorytmy formatowania generują tyle cyfr, ile jest wymaganych do reprezentowania wartości (lub wypełnienia określonej precyzji). Jako przykład poprawy; podczas drukowania dużej mocy dwóch elementów należy wziąć pod uwagę wyniki:

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

    Stare dane wyjściowe:

    1208925819614629200000000
    

    Nowe dane wyjściowe:

    1208925819614629174706176
    

    Stare algorytmy analizy rozważyłyby tylko 17 cyfr znaczących z ciągu wejściowego i odrzuciłyby resztę cyfr. Takie podejście jest wystarczające do wygenerowania bliskiego przybliżenia wartości reprezentowanej przez ciąg, a wynik jest zwykle bardzo zbliżony do poprawnie zaokrąglonego wyniku. Nowa implementacja uwzględnia wszystkie obecne cyfry i generuje poprawnie zaokrąglony wynik dla wszystkich danych wejściowych (do 768 cyfr długości). Ponadto te funkcje są teraz zgodne z trybem zaokrąglania (sterowane za pomocą fesetround). Jest to potencjalnie zmiana zachowania powodującego niezgodność, ponieważ te funkcje mogą zwracać różne wyniki. Nowe wyniki są zawsze bardziej poprawne niż stare wyniki.

  • Analizowanie szesnastkowe i nieskończoność/NaN

    Algorytmy analizowania zmiennoprzecinkowego będą teraz analizować ciągi zmiennoprzecinkowe szesnastkowe (takie jak te generowane przez specyfikatory formatu wydruku %a i %A) oraz wszystkie ciągi nieskończoności i ciągów NaN generowanych przez printf funkcje, zgodnie z powyższym opisem.

  • %A i %a zero dopełnienie

    Specyfikatory formatu %a i %A formatowania formatuje liczbę zmiennoprzecinkową jako mantissa szesnastkowa i wykładnik binarny. W poprzednich wersjach printf funkcje nieprawidłowo tworzyły ciągi zero-pad. Na przykład printf("%07.0a\n", 1.0) można wydrukować 00x1p+0, gdzie powinien drukować 0x01p+0. Ta wada została naprawiona.

  • %A i %a precyzja

    Domyślna precyzja specyfikatorów formatu %A i %a wynosiła 6 w poprzednich wersjach biblioteki. Domyślna precyzja wynosi teraz 13 w celu zachowania zgodności ze standardem C.

    Jest to zmiana zachowania środowiska uruchomieniowego w danych wyjściowych dowolnej funkcji, która używa ciągu formatu z %A lub %a. W starym zachowaniu dane wyjściowe używające specyfikatora %A mogą mieć wartość "1.1A2B3Cp+111". Teraz dane wyjściowe dla tej samej wartości to "1.1A2B3C4D5E6F7p+111". Aby uzyskać stare zachowanie, możesz określić precyzję, na przykład %.6A. Zobacz Specyfikacja precyzji.

  • Specyfikator %F

    Specyfikator formatu/konwersji %F jest teraz obsługiwany. Jest ona funkcjonalnie równoważna specyfikatorowi formatu %f, z tą różnicą, że wartości infiniacji i sieci NaN są formatowane przy użyciu liter wielkich.

    W poprzednich wersjach implementacja używana do analizowania F i N jako modyfikatorów długości. To zachowanie sięga epoki segmentowanych przestrzeni adresowych: te modyfikatory długości zostały użyte do wskazania odpowiednio daleko i blisko wskaźników, jak w %Fp lub %Ns. To zachowanie zostało usunięte. Jeśli plik %F zostanie napotkany, jest on teraz traktowany jako specyfikator formatu %F; Jeśli napotkano %N, jest on teraz traktowany jako nieprawidłowy parametr.

  • Formatowanie wykładnicze

    Specyfikatory formatu %e i %E formatować liczbę zmiennoprzecinkową jako mantysę dziesiętną i wykładnik. Specyfikatory formatu %g i %G również formatuje liczby w tym formularzu w niektórych przypadkach. W poprzednich wersjach CRT zawsze generowałby ciągi z trzycyfrowymi wykładnikami. Na przykład printf("%e\n", 1.0) można wydrukować 1.0000000e+000, co było niepoprawne. C wymaga, aby jeśli wykładnik jest reprezentowany przy użyciu tylko jednej lub dwóch cyfr, tylko dwie cyfry mają być drukowane.

    W programie Visual Studio 2005 dodano globalny przełącznik zgodności: _set_output_format. Program może wywołać tę funkcję z argumentem _TWO_DIGIT_EXPONENT, aby umożliwić zgodne drukowanie wykładnicze. Domyślne zachowanie zostało zmienione na zgodny ze standardami tryb drukowania wykładniczego.

  • Walidacja ciągu formatu

    W poprzednich wersjach printf funkcje i scanf dyskretnie akceptują wiele nieprawidłowych ciągów formatu, czasami z nietypowymi efektami. Na przykład %hlhlhlhld będzie traktowany jako %d. Wszystkie nieprawidłowe ciągi formatu są teraz traktowane jako nieprawidłowe parametry.

  • Walidacja ciągu trybu fopen

    W poprzednich wersjach fopen rodzina funkcji dyskretnie zaakceptowała niektóre nieprawidłowe ciągi trybu, takie jak r+b+. Nieprawidłowe ciągi trybu są teraz wykrywane i traktowane jako nieprawidłowe parametry.

  • tryb _O_U8TEXT

    Funkcja _setmode teraz prawidłowo zgłasza tryb otwartych strumieni in_O_U8TEXT. W poprzednich wersjach biblioteki raportowałby takie strumienie, jak otwierane w _O_WTEXT.

    Jest to zmiana powodująca niezgodność, jeśli kod interpretuje tryb _O_WTEXT dla strumieni, gdzie kodowanie to UTF-8. Jeśli aplikacja nie obsługuje UTF_8, rozważ dodanie obsługi tego coraz bardziej typowego kodowania.

  • snprintf i vsnprintf

    Funkcje snprintf i vsnprintf są teraz implementowane. Starszy kod często dostarczał wersje makr tych funkcji, ponieważ nie zostały zaimplementowane przez bibliotekę CRT, ale nie są już potrzebne w nowszych wersjach. Jeśli snprintf lub vsnprintf jest zdefiniowany jako makro przed dołączeniem <stdio.h>, kompilacja teraz kończy się niepowodzeniem z błędem wskazującym, gdzie zdefiniowano makro.

    Zwykle rozwiązaniem tego problemu jest usunięcie wszelkich deklaracji snprintf lub vsnprintf w kodzie użytkownika.

  • tmpnam generuje użyteczne nazwy plików

    W poprzednich wersjach tmpnam funkcje i tmpnam_s wygenerowały nazwy plików w katalogu głównym dysku (na przykład \sd3c.). Te funkcje generują teraz ścieżki nazw plików do użytku w katalogu tymczasowym.

  • Hermetyzacja PLIKÓW

    W poprzednich wersjach pełny typ PLIKU został zdefiniowany publicznie w <stdio.h>pliku , więc kod użytkownika mógł uzyskać dostęp do pliku i zmodyfikować jego elementy wewnętrzne. Biblioteka została zmieniona w celu ukrycia szczegółów implementacji. W ramach tej zmiany plik zdefiniowany w pliku <stdio.h> jest teraz nieprzezroczystym typem, a jego składowe są niedostępne spoza samego CRT.

  • _outp i _inp

    Funkcje _outp, _outpw, _outpd, _inp, _inpw i _inpd zostały usunięte.

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

  • strtof i wcstof

    strtof Nie można ustawić errno funkcji i wcstof na ERANGE, gdy wartość nie była reprezentowana jako zmiennoprzecinkowa. Ten błąd był specyficzny dla tych dwóch funkcji; funkcje strtod, wcstod, strtoldi wcstold nie zostały naruszone. Ten problem został rozwiązany i jest zmianą powodującą niezgodność w czasie wykonywania.

  • Funkcje alokacji wyrównane

    W poprzednich wersjach wyrównane funkcje alokacji (_aligned_malloc, _aligned_offset_mallocitp.) w trybie dyskretnym akceptują żądania dla bloku z wyrównaniem 0. Żądane wyrównanie musi być potęgą dwóch, która nie jest równa zero. Żądane wyrównanie wartości 0 jest teraz traktowane jako nieprawidłowy parametr. Ten problem został rozwiązany i jest zmianą powodującą niezgodność w czasie wykonywania.

  • Funkcje stert

    _heapaddFunkcje , _heapseti _heapused zostały usunięte. Te funkcje były niefunkcjonalne od czasu aktualizacji CRT w celu korzystania z sterty systemu Windows.

  • smallheap

    smallheap Opcja łącza została usunięta. Zobacz Opcje łącza.

  • _Stat

    Rodzina _stat funkcji jest używana CreateFile w programie Visual Studio 2015 zamiast FindFirstFile w programie Visual Studio 2013 i starszych wersjach. Oznacza to, że _stat na ścieżce kończącej się ukośnikiem kończy się powodzeniem, jeśli ścieżka odwołuje się do katalogu, w przeciwieństwie do wcześniejszego wystąpienia błędu funkcji z ustawioną wartością errno ENOENT.

<string.h>

  • wcstok

    Podpis wcstok funkcji został zmieniony tak, aby był zgodny z wymaganiami standardu C. W poprzednich wersjach biblioteki podpis tej funkcji był następujący:

    wchar_t* wcstok(wchar_t*, wchar_t const*)
    

    Użyto wewnętrznego kontekstu na wątek do śledzenia stanu między wywołaniami, tak jak w przypadku strtokelementu . Funkcja ma teraz podpis wchar_t* wcstok(wchar_t*, wchar_t const*, wchar_t**)i wymaga od obiektu wywołującego przekazania kontekstu jako trzeciego argumentu do funkcji.

    Dodano nową _wcstok funkcję ze starym podpisem w celu ułatwienia przenoszenia. Podczas kompilowania kodu C++ istnieje również wbudowane przeciążenie wcstok , które ma stary podpis. To przeciążenie jest deklarowane jako przestarzałe. W kodzie języka C można define_CRT_NON_CONFORMING_WCSTOK przyczynę _wcstok użycia zamiast wcstokelementu .

<time.h>

  • clock

    W poprzednich wersjach clock funkcja została zaimplementowana przy użyciu interfejsu API GetSystemTimeAsFileTimesystemu Windows . Dzięki tej implementacji funkcja zegara była wrażliwa na czas systemowy i w związku z tym niekoniecznie monotoniczna. Funkcja zegara została ponownie zaimplementowana pod względem QueryPerformanceCounter i jest teraz monotoniczna.

  • fstat i _utime

    W poprzednich wersjach _statfunkcje , fstati _utime obsługują niepoprawnie czas letni. Przed programem Visual Studio 2013 wszystkie te funkcje nieprawidłowo dostosowywać czas standardowy tak, jakby były w czasie letnim.

    W programie Visual Studio 2013 problem został rozwiązany w _stat rodzinie funkcji, ale podobne problemy w fstat rodzinach funkcji i _utime nie zostały rozwiązane. Ta częściowa poprawka doprowadziła do problemów z powodu niespójności między funkcjami. Rodziny fstat funkcji i _utime zostały naprawione, więc wszystkie te funkcje obsługują teraz czas letni prawidłowo i spójnie.

  • asctime

    W poprzednich wersjach funkcja będzie asctime zawierać jednocyfrowe dni z wiodącym zerem, na przykład: Fri Jun 06 08:00:00 2014. Specyfikacja wymaga, aby takie dni zostały wypełnione spacją wiodącą, jak w pliku Fri Jun 6 08:00:00 2014. Ten problem został rozwiązany.

  • strftime i wcsftime

    Funkcje strftime i wcsftime obsługują teraz specyfikatory formatu %C, %D, %e, %F, %g, %G, %h, %n, %r, %R, %t, %T, %u i %V. Ponadto modyfikatory E i O są analizowane, ale ignorowane.

    Specyfikator formatu %c jest określony jako tworzący "odpowiednią reprezentację daty i godziny" dla bieżących ustawień regionalnych. W ustawieniach regionalnych języka C ta reprezentacja musi być taka sama jak %a %b %e %T %Y, taka sama forma, jak w przypadku asctimeelementu . W poprzednich wersjach specyfikator formatu %c niepoprawnie sformatowany przy użyciu MM/DD/YY HH:MM:SS reprezentacji. Ten problem został rozwiązany.

  • czas i TIME_UTC

    Nagłówek <time.h> definiuje timespec teraz typ i timespec_get funkcję z C11 Standard. Ponadto makro TIME_UTC do użycia z funkcją timespec_get jest teraz zdefiniowane. Ta aktualizacja to zmiana powodująca niezgodność dla kodu, która zawiera definicję powodującą konflikt dla dowolnego z tych identyfikatorów.

  • CLOCKS_PER_SEC

    Makro CLOCKS_PER_SEC teraz rozszerza się na liczbę całkowitą typu clock_t, zgodnie z wymaganiami języka C.

Standardowa biblioteka C++

Aby włączyć nowe optymalizacje i kontrole debugowania, implementacja standardowej biblioteki C++ w Visual Studio celowo łamie zgodność binarną między wersjami. W związku z tym gdy używana jest standardowa biblioteka C++, pliki obiektowe i biblioteki statyczne, które są kompilowane przy użyciu różnych wersji, nie mogą być mieszane w jednym pliku binarnym (EXE lub DLL), a obiekty standardowej biblioteki C++ nie mogą być przekazywane między plikami binarnymi, które są kompilowane przy użyciu różnych wersji. Takie mieszanie powoduje błędy konsolidatora dotyczące niezgodności _MSC_VER. (_MSC_VER to makro, które zawiera wersję główną kompilatora — na przykład 1800 dla programu Visual Studio 2013). To sprawdzenie nie może wykryć mieszania bibliotek DLL i nie może wykryć mieszania, które obejmuje program Visual Studio 2008 lub starszy.

  • Standardowa biblioteka C++ zawiera pliki

    Wprowadzono pewne zmiany w strukturze dołączania w nagłówkach biblioteki standardowej języka C++. Nagłówki standardowej biblioteki języka C++ mogą zawierać się nawzajem na nieokreślone sposoby. Ogólnie rzecz biorąc, należy napisać kod, tak aby dokładnie zawierał wszystkie nagłówki, których potrzebuje zgodnie ze standardem C++, i nie polegają na tym, które nagłówki standardowej biblioteki języka C++ zawierają inne nagłówki biblioteki standardowej języka C++. Dzięki temu kod jest przenośny w różnych wersjach i platformach. Co najmniej dwie zmiany nagłówka w programie Visual Studio 2015 wpływają na kod użytkownika. <string> Najpierw nie zawiera <iterator>już elementu . <tuple> Po drugie, teraz deklaruje std::array bez uwzględniania wszystkich <array>elementów , które mogą podzielić kod za pomocą następującej kombinacji konstrukcji kodu: kod ma zmienną o nazwie "array", i masz dyrektywę "using namespace std;" i dołączasz nagłówek biblioteki standardowej języka C++ (na przykład <functional>), który zawiera <tuple>element , który teraz deklaruje std::array.

  • steady_clock

    steady_clock Implementacja <chrono> programu została zmieniona tak, aby spełniała standardowe wymagania języka C++ dotyczące niestabilności i monotoniczności. steady_clock element jest teraz oparty na QueryPerformanceCounter parametrze i high_resolution_clock jest teraz definicją typów dla elementu steady_clock. W związku z tym w programie Visual Studio steady_clock::time_point jest teraz definicją chrono::time_point<steady_clock>typu , jednak niekoniecznie jest to przypadek innych implementacji.

  • alokatory i const

    Teraz wymagamy porównania równości/nierówności alokatora, aby zaakceptować argumenty const po obu stronach. Jeśli alokatorzy definiują te operatory w następujący sposób,

    bool operator==(const MyAlloc& other)
    

    następnie należy je zaktualizować i zadeklarować jako elementy członkowskie const:

    bool operator==(const MyAlloc& other) const
    
  • const, elementy

    Standard C++ zawsze ma zabronione kontenery elementów const (takich jak vector<const T> lub set<const T>). Program Visual Studio 2013 i wcześniejsze zaakceptował takie kontenery. W bieżącej wersji takie kontenery nie mogą być kompilowane.

  • std::allocator::d eallocate

    W programie Visual Studio 2013 i starszych std::allocator::deallocate(p, n) zignorowano argument przekazany dla n. Standardowa języka C++ zawsze wymagała, aby n musi być równe wartości przekazanej jako pierwszy argument wywołania allocatemetody , która zwróciła wartość p. Jednak w bieżącej wersji wartość n jest sprawdzana. Kod przekazujący argumenty dla n , które różnią się od tego, czego wymaga standard, może ulec awarii w czasie wykonywania.

  • hash_map i hash_set

    Niestandardowe pliki <hash_map> nagłówkowe i <hash_set> są przestarzałe w programie Visual Studio 2015 i zostaną usunięte w przyszłej wersji. Użyj i <unordered_map> <unordered_set> zamiast tego.

  • komparatory i operatory()

    Kontenery asocjacyjne ( <map> rodzina) wymagają teraz, aby ich komparatory miały operatory wywołań funkcji const-callable. Nie można skompilować następującego kodu w deklaracji klasy kompilatora:

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

    Aby rozwiązać ten błąd, zmień deklarację funkcji na:

    bool operator()(const X& a, const X& b) const
    
  • cechy typu

    Stare nazwy cech typów z wcześniejszej wersji standardu roboczego języka C++ zostały usunięte. Zostały one zmienione w języku C++11 i zostały zaktualizowane do wartości języka C++11 w programie Visual Studio 2015. W poniższej tabeli przedstawiono stare i nowe nazwy.

    Stara nazwa Nowa nazwa
    add_reference add_lvalue_reference
    has_default_constructor is_default_constructible
    has_copy_constructor is_copy_constructible
    has_move_constructor is_move_constructible
    has_nothrow_constructor is_nothrow_default_constructible
    has_nothrow_default_constructor is_nothrow_default_constructible
    has_nothrow_copy is_nothrow_copy_constructible
    has_nothrow_copy_constructor is_nothrow_copy_constructible
    has_nothrow_move_constructor is_nothrow_move_constructible
    has_nothrow_assign is_nothrow_copy_assignable
    has_nothrow_copy_assign is_nothrow_copy_assignable
    has_nothrow_move_assign is_nothrow_move_assignable
    has_trivial_constructor is_trivially_default_constructible
    has_trivial_default_constructor is_trivially_default_constructible
    has_trivial_copy is_trivially_copy_constructible
    has_trivial_move_constructor is_trivially_move_constructible
    has_trivial_assign is_trivially_copy_assignable
    has_trivial_move_assign is_trivially_move_assignable
    has_trivial_destructor is_trivially_destructible
  • launch::any i launch::sync policies

    Niestandardowe launch::any zasady i launch::sync zasady zostały usunięte. Zamiast tego dla launch::anyparametru użyj polecenia launch:async | launch:deferred. W przypadku launch::syncprogramu użyj polecenia launch::deferred. Zobacz launch Enumeration (Wyliczenie uruchamiania).

MFC i ATL

  • Microsoft Foundation Classes (MFC)

    Nie jest już uwzględniana w instalacji "Typowe" programu Visual Studio ze względu na jego duży rozmiar. Aby zainstalować MFC, wybierz opcję Instalacji niestandardowej w instalatorze programu Visual Studio 2015. Jeśli masz już zainstalowany program Visual Studio 2015, możesz zainstalować MFC, uruchamiając ponownie instalatora programu Visual Studio . Wybierz opcję Instalacja niestandardowa, a następnie wybierz pozycję Klasy programu Microsoft Foundation. Konfigurację programu Visual Studio można uruchomić z poziomu Panel sterowania kontrolki Programy i funkcje lub z nośnika instalacyjnego.

    Pakiet redystrybucyjny Visual C++ wciąż zawiera tę bibliotekę.

Współbieżność środowiska wykonawczego

  • Zwracanie makra z pliku Windows.h powodujące konflikt ze współbieżnością::Context::Yield

    Środowisko uruchomieniowe współbieżności używane #undef wcześniej do niezdefiniowania makra Yield w celu uniknięcia konfliktów między makrem Yield zdefiniowanym w systemie Windows.h i concurrency::Context::Yield funkcji. Zostało to #undef usunięte, a dodano nową równoważną współbieżność wywołania interfejsu API, która nie powoduje konfliktu::Context::YieldExecution . Aby obejść konflikty z metodą Yield, możesz zaktualizować kod w celu wywołania YieldExecution funkcji lub otoczyć Yield nazwę funkcji nawiasami w lokacjach wywołania, jak w poniższym przykładzie:

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

Ulepszenia zgodności kompilatora w programie Visual Studio 2015

Podczas uaktualniania kodu z poprzednich wersji mogą również wystąpić błędy kompilatora, które są spowodowane ulepszeniami zgodności w programie Visual Studio 2015. Te ulepszenia nie powodują przerwania zgodności binarnej z wcześniejszych wersji programu Visual Studio, ale mogą generować błędy kompilatora, w których żadne z nich nie były emitowane wcześniej. Aby uzyskać więcej informacji, zobacz Visual C++ What's New 2003 to 2015 (Co nowego w wersji od 2003 do 2015).

W programie Visual Studio 2015 ciągłe ulepszenia zgodności kompilatora mogą czasami zmieniać sposób zrozumienia istniejącego kodu źródłowego przez kompilator. W związku z tym podczas kompilacji mogą wystąpić nowe lub różne błędy, a nawet różnice behawioralne w kodzie, który wcześniej skompilował i wydawał się działać poprawnie.

Na szczęście te różnice nie mają wpływu na większość kodu źródłowego. Gdy kod źródłowy lub inne zmiany są potrzebne do rozwiązania tych różnic, poprawki wydają się być małe i proste. Dołączyliśmy wiele przykładów wcześniej akceptowalnego kodu źródłowego, które mogą wymagać zmiany (przed) i poprawek w celu ich poprawienia (po).

Chociaż te różnice mogą mieć wpływ na kod źródłowy lub inne artefakty kompilacji, nie mają wpływu na zgodność binarną między aktualizacjami wersji programu Visual Studio. Zmiana powodująca niezgodność jest poważniejsza i może mieć wpływ na zgodność binarną, ale tego rodzaju przerwy w zgodności binarnej występują tylko między głównymi wersjami programu Visual Studio, na przykład między programem Visual Studio 2013 i programem Visual Studio 2015. Aby uzyskać informacje na temat zmian powodujących niezgodność w programach Visual Studio 2013 i Visual Studio 2015, zobacz Visual Studio 2015 Conformance Changes (Zmiany zgodności programu Visual Studio 2015).

Ulepszenia zgodności w programie Visual Studio 2015

  • /Zc:forScope- opcja

    Opcja /Zc:forScope- kompilatora jest przestarzała i zostanie usunięta w przyszłej wersji.

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

    Zazwyczaj ta opcja została użyta w celu zezwolenia na niestandardowy kod, który używa zmiennych pętli po punkcie, w którym, zgodnie ze standardem, powinny one zniknąć z zakresu. To było konieczne tylko wtedy, gdy skompilowano z opcją /Za , ponieważ bez /Za, użycie zmiennej for dla pętli po zakończeniu pętli jest zawsze dozwolone. Jeśli nie interesuje Cię zgodność ze standardami (na przykład jeśli kod nie jest przeznaczony do przenoszenia do innych kompilatorów), możesz wyłączyć /Za opcję (lub ustawić właściwość Wyłącz rozszerzenia językowe na Nie). Jeśli dbasz o pisanie przenośnego, zgodnego ze standardami kodu, należy ponownie napisać kod, tak aby był zgodny ze standardem, przenosząc deklarację takich zmiennych do punktu poza pętlą.

    // 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 Opcja kompilatora

    Opcja kompilatora /Zg (Generuj prototypy funkcji) nie jest już dostępna. Ta opcja kompilatora była wcześniej przestarzała.

  • Nie można już uruchamiać testów jednostkowych za pomocą języka C++/interfejsu wiersza polecenia z mstest.exe. Zamiast tego użyj vstest.console.exe. Zobacz VSTest.Console.exe opcje wiersza polecenia.

  • modyfikowalne słowo kluczowe

    Specyfikator mutable klasy magazynu nie jest już dozwolony w miejscach, w których wcześniej skompilowane bez błędu. Teraz kompilator zwraca błąd C2071 (nielegalna klasa magazynu). Zgodnie ze standardem specyfikator mutable może być stosowany tylko do nazw składowych danych klasy i nie można ich stosować do nazw zadeklarowanych jako const lub static i nie można ich zastosować do składowych odwołań.

    Rozważmy na przykład następujący kod:

    struct S
    {
        mutable int &r;
    };
    

    Poprzednie wersje kompilatora zaakceptowały to, ale teraz kompilator daje następujący błąd:

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

    Aby naprawić błąd, usuń nadmiarowe mutable słowo kluczowe.

  • char_16_t i char32_t

    Nie można już używać char16_t char32_t aliasów ani jako aliasów w elemecie typedef, ponieważ te typy są teraz traktowane jako wbudowane. Często zdarzało się, że użytkownicy i autorzy bibliotek definiują char16_t char32_t odpowiednio i jako aliasy uint16_t elementów i 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;
    }
    

    Aby zaktualizować kod, usuń typedef deklaracje i zmień nazwy innych identyfikatorów, które zderzają się z tymi nazwami.

  • Parametry szablonu innego niż typ

    Określony kod, który obejmuje parametry szablonu innego niż typ, jest teraz poprawnie sprawdzany pod kątem zgodności typów po podaniu jawnych argumentów szablonu. Na przykład poniższy kod skompilowany bez błędu w poprzednich wersjach programu 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>();
    }
    

    Bieżący kompilator poprawnie wyświetla błąd, ponieważ typ parametru szablonu nie jest zgodny z argumentem szablonu (parametr jest wskaźnikiem do elementu członkowskiego const, ale funkcja f jest inny niż const):

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

    Aby rozwiązać ten błąd w kodzie, upewnij się, że typ używanego argumentu szablonu pasuje do zadeklarowanego typu parametru szablonu.

  • __declspec(align)

    Kompilator nie akceptuje __declspec(align) już funkcji. Ta konstrukcja była zawsze ignorowana, ale teraz generuje błąd kompilatora.

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

    Aby rozwiązać ten problem, usuń z __declspec(align) deklaracji funkcji. Ponieważ nie miało to żadnego wpływu, usunięcie go nie zmienia.

  • Obsługa wyjątków

    Istnieje kilka zmian obsługi wyjątków. Najpierw obiekty wyjątków muszą być kopiowalne lub wymienne. Poniższy kod skompilowany w programie Visual Studio 2013, ale nie jest kompilowany w programie Visual Studio 2015:

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

    Problem polega na tym, że konstruktor kopiujący jest prywatny, więc nie można skopiować obiektu w normalny sposób obsługi wyjątku. To samo dotyczy, gdy konstruktor kopiujący jest zadeklarowany explicit.

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

    Aby zaktualizować kod, upewnij się, że konstruktor kopiujący dla obiektu wyjątku nie jest public oznaczony explicitjako .

    Przechwycenie wyjątku według wartości wymaga również skopiowania obiektu wyjątku. Poniższy kod skompilowany w programie Visual Studio 2013, ale nie jest kompilowany w programie Visual Studio 2015:

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

    Ten problem można rozwiązać, zmieniając typ parametru catch dla odwołania.

    catch (D& d)
    {
    }
    
  • Literały ciągu, po których następują makra

    Kompilator obsługuje teraz literały zdefiniowane przez użytkownika. W związku z tym literały ciągów, po których następują makra bez żadnych interweniujących białych znaków, są interpretowane jako literały zdefiniowane przez użytkownika, co może powodować błędy lub nieoczekiwane wyniki. Na przykład w poprzednich kompilatorach następujący kod został pomyślnie skompilowany:

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

    Kompilator zinterpretował ten kod jako literał ciągu "hello", po którym następuje makro, które zostało rozwinięte w "tam", a następnie dwa literały ciągu zostały łączone w jeden. W programie Visual Studio 2015 kompilator interpretuje tę sekwencję jako literał zdefiniowany przez użytkownika, ale ponieważ nie zdefiniowano pasującego literału _x zdefiniowanego przez użytkownika, zwraca błąd.

    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?
    

    Aby rozwiązać ten problem, dodaj spację między literałem ciągu a makrem.

  • Sąsiadujące literały ciągu

    Podobnie jak poprzednio, ze względu na powiązane zmiany w analizowaniu ciągów, sąsiadujące literały ciągu (szerokie lub wąskie literały ciągu) bez żadnych białych znaków zostały zinterpretowane jako pojedynczy połączony ciąg w poprzednich wersjach Visaul C++. W programie Visual Studio 2015 należy teraz dodać biały znak między dwoma ciągami. Na przykład należy zmienić następujący kod:

    char * str = "abc""def";
    

    Aby rozwiązać ten problem, dodaj spację między dwoma ciągami:

    char * str = "abc" "def";
    
  • Umieszczanie nowych i usuwanie

    Wprowadzono zmianę operatora delete w celu zapewnienia zgodności z standardem C++14. Szczegółowe informacje o zmianach standardów można znaleźć w artykule C++ Size Deallocation (Alokacja rozmiaru języka C++). Zmiany dodają postać operatora globalnego delete , który przyjmuje parametr rozmiaru. Zmiana powodująca niezgodność polega na tym, że jeśli wcześniej używano operatora delete z tym samym podpisem (aby odpowiadać nowemu operatorowi umieszczania), zostanie wyświetlony błąd kompilatora (C2956, który występuje w momencie użycia nowego umieszczania, ponieważ jest to pozycja w kodzie, w którym kompilator próbuje zidentyfikować odpowiedni operator dopasowaniadelete).

    Funkcja void operator delete(void *, size_t) była operatorem usuwania umieszczania odpowiadającym nowej funkcji void * operator new(size_t, size_t) umieszczania w języku C++11. W przypadku cofnięcia przydziału rozmiaru języka C++14 ta funkcja usuwania jest teraz zwykłą funkcją cofania transakcji (operator globalnydelete). Standard wymaga, aby jeśli użycie funkcji umieszczania nowego wyszukuje odpowiednią funkcję usuwania i znajduje zwykłą funkcję cofania transakcji, program jest źle sformułowany.

    Załóżmy na przykład, że kod definiuje zarówno umieszczenie nowego, jak i usunięcie umieszczania:

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

    Problem występuje z powodu dopasowania podpisów funkcji między zdefiniowanym operatorem usuwania umieszczania i nowym operatorem rozmiaru delete globalnego. Zastanów się, czy można użyć innego typu niż size_t w przypadku dowolnego umieszczania nowych operatorów i delete . Typ obiektu size_t typedef jest zależny od kompilatora. Jest on elementem typedef for unsigned int w środowisku MSVC. Dobrym rozwiązaniem jest użycie wyliczonego typu, takiego jak ten:

    enum class my_type : size_t {};
    

    Następnie zmień definicję umieszczania nowego i delete użyj tego typu jako drugiego argumentu size_tzamiast . Należy również zaktualizować wywołania, aby umieścić nowe, aby przekazać nowy typ (na przykład za pomocą polecenia static_cast<my_type> , aby przekonwertować wartość z liczby całkowitej) i zaktualizować definicję new i delete rzutować z powrotem do typu liczby całkowitej. Nie musisz używać elementu enum dla tego elementu; typ klasy z elementem size_t członkowskim również będzie działać.

    Alternatywną rozwiązaniem jest możliwość całkowitego wyeliminowania umieszczania. Jeśli kod używa funkcji umieszczania nowego w celu zaimplementowania puli pamięci, w której argument umieszczania jest rozmiarem przydzielonego lub usuniętego obiektu, rozmiar funkcji cofania może być odpowiedni do zastąpienia własnego niestandardowego kodu puli pamięci i można pozbyć się funkcji umieszczania i po prostu użyć własnego operatora dwóch argumentów delete zamiast funkcji umieszczania.

    Jeśli nie chcesz natychmiast aktualizować kodu, możesz przywrócić stare zachowanie przy użyciu opcji /Zc:sizedDealloc-kompilatora . Jeśli używasz tej opcji, funkcje usuwania dwóch argumentów nie istnieją i nie spowodują konfliktu z operatorem usuwania umieszczania.

  • Składowe danych unii

    Składowe danych związków nie mogą już mieć typów odwołań. Poniższy kod został pomyślnie skompilowany w programie Visual Studio 2013, ale generuje błąd w programie Visual Studio 2015.

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

    Powyższy kod generuje następujące błędy:

    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
    

    Aby rozwiązać ten problem, zmień typy odwołań na wskaźnik lub wartość. Zmiana typu na wskaźnik wymaga zmian w kodzie, który używa pola unii. Zmiana kodu na wartość spowoduje zmianę danych przechowywanych w unii, co wpływa na inne pola, ponieważ pola w typach unii współdzielą tę samą pamięć. W zależności od rozmiaru wartości może również zmienić rozmiar unii.

  • Anonimowe związki zawodowe są teraz bardziej zgodne ze standardem. Poprzednie wersje kompilatora wygenerowały jawny konstruktor i destruktor dla anonimowych związków. Te funkcje generowane przez kompilator są usuwane w programie Visual Studio 2015.

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

    Powyższy kod generuje następujący błąd w programie 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
    

    Aby rozwiązać ten problem, podaj własne definicje konstruktora i/lub destruktora.

    struct S
    {
        // Provide a default constructor by adding an empty function body.
        S() {}
    };
    
    union
    {
        struct
        {
            S s;
        };
    } u;
    
  • Związki z anonimowymi strukturami

    Aby zachować zgodność ze standardem, zachowanie środowiska uruchomieniowego zmieniło się dla elementów członkowskich struktur anonimowych w związkach. Konstruktor dla anonimowych składowych struktury w unii nie jest już niejawnie wywoływany po utworzeniu takiego związku. Ponadto destruktor anonimowych składowych struktury w unii nie jest już niejawnie wywoływany, gdy związek wykracza poza zakres. Rozważmy następujący kod, w którym unia U zawiera anonimową strukturę zawierającą nazwaną strukturę składową S, która ma destruktora.

    #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;
    }
    

    W programie Visual Studio 2013 konstruktor dla języka S jest wywoływany podczas tworzenia unii, a destruktor dla języka S jest wywoływany, gdy stos funkcji f jest czyszczony. Jednak w programie Visual Studio 2015 konstruktor i destruktor nie są wywoływane. Kompilator wyświetla ostrzeżenie dotyczące tej zmiany zachowania.

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

    Aby przywrócić oryginalne zachowanie, nadaj strukturze anonimowej nazwę. Zachowanie środowiska uruchomieniowego struktur innych niż anonimowe jest takie samo, niezależnie od wersji kompilatora.

    #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;
    }
    

    Alternatywnie spróbuj przenieść konstruktor i kod destruktora do nowych funkcji i dodać wywołania do tych funkcji z konstruktora i destruktora dla unii.

    #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;
    }
    
  • Rozpoznawanie szablonu

    Wprowadzono zmiany w rozpoznawaniu nazw dla szablonów. W języku C++, biorąc pod uwagę kandydatów do rozpoznawania nazwy, może się okazać, że co najmniej jedna nazwa uwzględniana jako potencjalne dopasowania powoduje utworzenie nieprawidłowego wystąpienia szablonu. Te nieprawidłowe wystąpienia zwykle nie powodują błędów kompilatora, zasady znanej jako SFINAE (Niepowodzenie podstawiania nie jest błędem).

    Jeśli teraz sfINAE wymaga, aby kompilator tworzył wystąpienie specjalizacji szablonu klasy, wszelkie błędy występujące podczas tego procesu to błędy kompilatora. W poprzednich wersjach kompilator zignorowałby takie błędy. Rozważmy na przykład następujący kod:

    #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);
    }
    

    Jeśli kompilujesz przy użyciu bieżącego kompilatora, wystąpi następujący błąd:

    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
    ]
    

    Wynika to z faktu, że w momencie pierwszego wywołania is_base_of klasa D nie została jeszcze zdefiniowana.

    W takim przypadku poprawka polega na tym, aby nie używać takich cech typu do momentu zdefiniowania klasy. Jeśli przeniesiesz definicje B i D na początek pliku kodu, błąd zostanie rozwiązany. Jeśli definicje znajdują się w plikach nagłówków, sprawdź kolejność instrukcji include dla plików nagłówków, aby upewnić się, że wszystkie definicje klas są kompilowane przed użyciem problematycznych szablonów.

  • Konstruktory kopii

    W programach Visual Studio 2013 i Visual Studio 2015 kompilator generuje konstruktor kopii dla klasy, jeśli ta klasa ma konstruktor przenoszenia zdefiniowany przez użytkownika, ale nie zdefiniowano konstruktora kopiowania zdefiniowanego przez użytkownika. W usłudze Dev14 ten niejawnie wygenerowany konstruktor kopiowania jest również oznaczony jako "= delete".

  • parametr main zadeklarowany jako extern "C" wymaga teraz typu zwracanego.

    Poniższy kod generuje teraz kod C4430.

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

    Aby naprawić błąd, dodaj zwracany typ:

    extern "C" int __cdecl main(){} // OK
    
  • typename nie jest dozwolona w inicjatorze składowym

    Poniższy kod tworzy teraz kod C2059:

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

    Aby naprawić błąd, usuń element typename z inicjatora:

    S1() : T::type() // OK
    ...
    
  • Klasa magazynu w przypadku jawnych specjalizacji jest ignorowana.

    W poniższym kodzie specyfikator klasy magazynu statycznego jest ignorowany

    template <typename T>
    void myfunc(T h)
    {
    }
    
    template<>
    static void myfunc(double h) // static is ignored
    {
    }
    
  • Stała używana w static_assert wewnątrz szablonu klasy zawsze kończy się niepowodzeniem.

    Poniższy kod powoduje, że polecenie zawsze kończy się niepowodzeniem static_assert :

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

    Aby obejść ten problem, zawijaj wartość w obiekcie 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
    
  • Reguły wymuszane dla deklaracji przesyłania dalej. (Dotyczy tylko C.)

    Poniższy kod generuje teraz kod C2065:

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

    Aby rozwiązać ten problem, dodaj odpowiednie deklaracje przekazywania:

    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);
    
  • Bardziej spójne wymuszanie typów wskaźników funkcji

    Poniższy kod tworzy teraz kod C2197:

    typedef int(*F1)(int);
    typedef int(*F2)(int, int);
    
    void func(F1 f, int v1, int v2)
    {
        f(v1, v2); // C2197
    }
    
  • Niejednoznaczne wywołania funkcji przeciążonych

    Poniższy kod tworzy teraz kod C266: "N::bind": niejednoznaczne wywołanie funkcji przeciążonej

    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
        }
    };
    

    Aby rozwiązać ten problem, możesz w pełni zakwalifikować wywołanie do bind: N::bind(...). Jeśli jednak ta zmiana jest manifestem za pomocą niezdecydowanego identyfikatora (C2065), może być konieczne naprawienie tej zmiany za pomocą using deklaracji.

    Ten wzorzec występuje często w przypadku języka ComPtr i innych typów w Microsoft::WRL przestrzeni nazw.

  • Naprawianie nieprawidłowego adresu

    Poniższy kod tworzy teraz kod C2440: '=': nie można przekonwertować z "typu *" na "typ". Aby naprawić błąd, zmień &(typ) na (typ) i (&f()) na (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());
    }
    
  • Literał ciągu jest tablicą stałą

    Poniższy kod generuje teraz kod C2664: "void f(void )': nie można przekonwertować argumentu 1 z "const char ()[2]" na "void *"

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

    Aby rozwiązać ten problem, zmień typ parametru funkcji na const void*, lub zmień treść h elementu , aby wyglądała następująco:

    void h(void)
    {
        char name[] = __FUNCTION__;
        f( name);
        void *p = &"";
    }
    
  • Ciągi UDL języka C++11

    Poniższy kod generuje teraz błąd C3688: nieprawidłowy sufiks literału "L"; Nie można odnaleźć operatora literału lub szablonu operatora literału "operator"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");
    }
    

    Aby naprawić błąd, zmień kod, aby dodać spację:

    #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");
    }
    

    W powyższym MACRO przykładzie nie jest już analizowany jako dwa tokeny (ciąg, po którym następuje makro). Teraz jest ona analizowana jako pojedynczy token UDL. To samo dotyczy L""L", który został przeanalizowany wcześniej jako L"" i L"", a teraz jest analizowany jako L""L i "".

    Reguły łączenia ciągów zostały również wprowadzone zgodnie ze standardem, co oznacza, że L"a" "b" jest odpowiednikiem L"ab". Poprzednie wersje programu Visual Studio nie akceptowały łączenia ciągów o innej szerokości znaków.

  • Usunięto pusty znak C++11

    Poniższy kod generuje teraz błąd C2137: stała pustego znaku

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

    Aby naprawić błąd, zmień kod, aby jawnie ustawić wartość null:

    bool check(wchar_t c){
        return c == L'\0';
    }
    
  • Wyjątki MFC nie mogą być przechwytywane według wartości, ponieważ nie można ich kopiować

    Następujący kod w aplikacji MFC powoduje teraz błąd C2316: "D": nie można przechwycić, ponieważ destruktor i/lub konstruktor kopiowania są niedostępne lub usunięte

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

    Aby naprawić kod, można zmienić blok catch na catch (const D &) , ale lepszym rozwiązaniem jest zwykle użycie makr TRY/CATCH MFC.

  • alignof jest teraz słowem kluczowym

    Poniższy kod generuje teraz błąd C2332: "class": brak nazwy tagu. Aby naprawić kod, musisz zmienić nazwę klasy lub, jeśli klasa wykonuje tę samą pracę co alignof, po prostu zastąp klasę nowym słowem kluczowym.

    class alignof{}
    
  • constexpr jest teraz słowem kluczowym

    Poniższy kod generuje teraz błąd C2059: błąd składni: ")". Aby naprawić kod, należy zmienić nazwę dowolnej funkcji lub nazw zmiennych, które są nazywane constexpr.

    int constexpr() {return 1;}
    
  • Typy wymienne nie mogą być const

    Gdy funkcja zwraca typ, który ma zostać przeniesiony, jego zwracany typ nie powinien mieć wartości const.

  • Usunięte konstruktory kopii

    Poniższy kod tworzy teraz kod C2280 "S::S(S(S &&)": próbuje odwołać się do usuniętej funkcji:

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

    Aby rozwiązać ten problem, użyj bezpośredniej inicjalizacji dla elementu S2:

    struct S{
        S(int, int);
        S(const S&) = delete;
        S(S&&) = delete;
    };
    
    S s2 = {2,3}; //OK
    
  • Konwersja na wskaźnik funkcji wygenerowany tylko wtedy, gdy nie przechwytywanie lambda

    Poniższy kod generuje kod C2664 w programie Visual Studio 2015.

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

    Aby naprawić błąd, usuń element = z listy przechwytywania.

  • Niejednoznaczne wywołania obejmujące operatory konwersji

    Poniższy kod generuje teraz błąd C2440: "rzutowanie typu": nie można przekonwertować z "S2" na "S1":

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

    Aby naprawić błąd, jawnie wywołaj operatora konwersji:

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

    Następujący kod generuje teraz błąd C2593: "operator =" jest niejednoznaczny:

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

    Aby naprawić błąd, jawnie wywołaj operatora konwersji:

    void f(S1 *p, S2 s)
    {
        *p = s.operator S1&();
    }
    
  • Naprawiono nieprawidłową inicjację kopiowania w inicjalizacji niestacjonalizowanej składowej danych (NSDMI)

    Następujący kod generuje teraz błąd C2664: "S1::S1(S1 &&)": nie można przekonwertować argumentu 1 z "bool" na "const S1 &":

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

    Aby naprawić błąd, użyj bezpośredniej inicjalizacji:

    struct S2 {
    S1 s1{true}; // OK
    };
    
  • Uzyskiwanie dostępu do konstruktorów wewnątrz instrukcji decltype

    Poniższy kod generuje teraz kod C2248: "S::S": nie można uzyskać dostępu do prywatnego elementu członkowskiego zadeklarowanej w klasie "S":

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

    Aby rozwiązać ten problem, dodaj deklarację znajomego elementu w S2 pliku :S

    class S {
        S();
        friend class S2; // Make S2 a friend
    public:
        int i;
    };
    
  • Domyślny obiekt ctor lambda jest niejawnie usuwany

    Poniższy kod generuje teraz błąd C3497: nie można skonstruować wystąpienia lambda:

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

    Aby naprawić błąd, usuń konieczność wywołania domyślnego konstruktora. Jeśli lambda nic nie przechwytuje, można go rzutować do wskaźnika funkcji.

  • Lambdas z usuniętym operatorem przypisania

    Poniższy kod generuje teraz błąd 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);
    }
    

    Aby naprawić błąd, zastąp element lambda klasą functor lub usuń konieczność użycia operatora przypisania.

  • Próba przeniesienia obiektu z usuniętym konstruktorem kopiowania

    Poniższy kod generuje teraz błąd C2280: "moveable::moveable(const moveable &)": próba odwołania się do usuniętej funkcji

    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;
    };
    

    Aby naprawić błąd, użyj std::move zamiast tego:

    S(moveable && m) :
        m_m(std::move(m))
    
  • Klasa lokalna nie może odwoływać się do innych klas lokalnych zdefiniowanych w dalszej części tej samej funkcji

    Poniższy kod generuje teraz błąd C2079: "s" używa niezdefiniowanej struktury "main::S2"

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

    Aby naprawić błąd, przenieś definicję S2elementu :

    int main()
    {
        struct S2 { //moved up
        };
    
    struct S1 {
        void f() {
            S2 s;
            }
        };
    }
    
  • Nie można wywołać chronionego ctora podstawowego w treści pochodnego obiektu ctor.

    Następujący kod generuje teraz błąd C2248: "S1::S1": nie można uzyskać dostępu do chronionej składowej zadeklarowanej w klasie "S1"

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

    Aby naprawić błąd, usuń S2 wywołanie S1() metody z konstruktora i w razie potrzeby umieść je w innej funkcji.

  • {} zapobiega konwersji na wskaźnik

    Poniższy kod generuje teraz kod C2439 "S::p": nie można zainicjować elementu członkowskiego

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

    Aby rozwiązać ten problem, usuń nawiasy klamrowe z wokół 0 polecenia lub zamiast tego użyj polecenia nullptr , jak pokazano w tym przykładzie:

    struct S {
        S() : p(nullptr) {}
        void *p;
    };
    
  • Nieprawidłowa definicja makra i użycie z nawiasami

    Poniższy przykład generuje teraz błąd C2008: ";": nieoczekiwany w definicji makr

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

    Aby rozwiązać ten problem, zmień górną linię na #define A();

    Następujący kod generuje błąd C2059: błąd składni: ")"

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

    Aby naprawić kod, usuń spację między elementami A i ().

    Następujący kod generuje błąd C2091: funkcja zwraca funkcję:

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

    Aby naprawić błąd, usuń nawiasy po zadeklarowaniu w S: DECLARE;.

    Następujący kod generuje błąd C2062: nieoczekiwany typ "int"

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

    Aby rozwiązać ten problem, zdefiniuj następujące elementy A :

    #define A int
    
  • Dodatkowe parensy w deklaracjach

    Następujący kod generuje błąd C2062: nieoczekiwany typ "int"

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

    Aby naprawić błąd, usuń nawiasy wokół jelementu . Jeśli nawiasy są potrzebne do jasności, użyj elementu typedef.

  • Konstruktory generowane przez kompilator i __declspec (novtable)

    W programie Visual Studio 2015 istnieje zwiększone prawdopodobieństwo, że konstruktory wbudowane w kompilatorze klas abstrakcyjnych z wirtualnymi klasami bazowymi mogą uwidocznić nieprawidłowe użycie __declspec(novtable) funkcji w przypadku użycia w połączeniu z elementem __declspec(dllimport).

  • auto wymaga pojedynczego wyrażenia w inicjowaniu listy bezpośredniej

    Poniższy kod generuje teraz błąd C3518: "testPositions": w kontekście inicjowania listy bezpośredniej typ "auto" można odwieść tylko z pojedynczego wyrażenia inicjatora

    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}
    };
    

    Aby naprawić błąd, jedną z możliwości jest zainicjowanie testPositions w następujący sposób:

    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}
    };
    
  • Sprawdzanie typów a wskaźniki do typów dla is_convertible

    Poniższy kod powoduje teraz niepowodzenie asercji statycznej.

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

    Aby naprawić błąd, zmień element static_assert tak, aby porównał wskaźniki z elementami D i B2:

    static_assert(std::is_convertible<D*, B2*>::value, "fail");
    
  • deklaracje __declspec (novtable) muszą być spójne

    __declspec deklaracje muszą być spójne we wszystkich bibliotekach. Poniższy kod spowoduje teraz wygenerowanie naruszenia reguły jednej definicji (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;
    

Ulepszenia zgodności w aktualizacji Update 1

  • Prywatne wirtualne klasy bazowe i dziedziczenie pośrednie

    Poprzednie wersje kompilatora zezwalały klasie pochodnej na wywoływanie funkcji składowych jej pośrednio pochodnych private virtual klas bazowych. To stare zachowanie było nieprawidłowe i nie jest zgodne ze standardem C++. Kompilator nie akceptuje już kodu napisanego w ten sposób i w rezultacie wystawia błąd kompilatora C2280.

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

    Przykład (przed)

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

    Przykład (po)

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

    - lub -

    class base;  // as above
    
    class middle : private virtual base {};
    class top : public virtual middle, private virtual bottom {};
    
    void destroy(top *p)
    {
        delete p;
    }
    
  • Przeciążony operator new and operator delete

    Poprzednie wersje kompilatora zezwalały na usunięcie operatora innego niż składowe nowego i innego niż składowe jako statyczne i zadeklarowane w przestrzeniach nazw innych niż globalna przestrzeń nazw. To stare zachowanie spowodowało ryzyko, że program nie będzie wywoływać implementacji operatora lub delete zamierzonej new przez programistę, co spowodowało dyskretne złe zachowanie środowiska uruchomieniowego. Kompilator nie akceptuje już kodu napisanego w ten sposób i zamiast tego wystawia błąd kompilatora 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.
    

    Przykład (przed)

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

    Przykład (po)

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

    Ponadto, mimo że kompilator nie daje określonej diagnostyki, operator new wbudowany jest uznawany za źle sformułowany.

  • Wywoływanie metody " operator type()" (konwersja zdefiniowana przez użytkownika) w typach innych niż klasy

    Poprzednie wersje kompilatora zezwalały na wywoływanie typów nieklasowych "operator type()" przy dyskretnym ignorowaniu. To stare zachowanie spowodowało ryzyko dyskretnego generowania nieprawidłowego kodu, co spowodowało nieprzewidywalne zachowanie środowiska uruchomieniowego. Kompilator nie akceptuje już kodu napisanego w ten sposób i zamiast tego wystawia błąd kompilatora C2228.

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

    Przykład (przed)

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

    Przykład (po)

    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'
    }
    
  • Nadmiarowa nazwa typu w specyfikatorach typów opracowanych

    Poprzednie wersje kompilatora dozwolone typename w opracowanym specyfikatorze typu, ale kod napisany w ten sposób jest semantycznie niepoprawny. Kompilator nie akceptuje już kodu napisanego w ten sposób i zamiast tego wystawia błąd kompilatora C3406.

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

    Przykład (przed)

    template <typename class T>
    class container;
    

    Przykład (po)

    template <class T>  // alternatively, could be 'template <typename T>'; 'typename' is not elaborating a type specifier in this case
    class container;
    
  • Potrącenie typów tablic z listy inicjatorów

    Poprzednie wersje kompilatora nie obsługiwały odliczania typów tablic z listy inicjatorów. Kompilator obsługuje teraz tę formę potrącenia typu, a w związku z tym wywołania szablonów funkcji przy użyciu list inicjatora mogą być teraz niejednoznaczne lub inne przeciążenie może zostać wybrane niż w poprzednich wersjach kompilatora. Aby rozwiązać te problemy, program musi teraz jawnie określić przeciążenie przeznaczone przez programistę.

    Gdy to nowe zachowanie powoduje, że rozwiązanie przeciążenia uwzględnia dodatkowego kandydata, który jest równie dobry jak kandydat historyczny, wywołanie staje się niejednoznaczne, a w rezultacie błąd kompilatora problemów kompilatora C2668.

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

    Przykład 1: Niejednoznaczne wywołanie funkcji przeciążonej (przed)

    // 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
    }
    

    Przykład 1: niejednoznaczne wywołanie przeciążonej funkcji (po)

    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);
    }
    

    Gdy to nowe zachowanie powoduje przeciążenie rozpoznawania, aby rozważyć dodatkowego kandydata, który jest lepszym dopasowaniem niż historyczny kandydat, wywołanie rozwiązuje się jednoznacznie z nowym kandydatem, powodując zmianę zachowania programu, która prawdopodobnie różni się od zamierzonego przez programistę.

    Przykład 2: zmiana rozdzielczości przeciążenia (przed)

    // 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 });
    }
    

    Przykład 2: zmiana rozdzielczości przeciążenia (po)

    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 });
    }
    
  • Przywracanie ostrzeżeń instrukcji switch

    Poprzednia wersja kompilatora usunęła niektóre ostrzeżenia związane z switch instrukcjami. Te ostrzeżenia zostały przywrócone. Kompilator wystawia teraz przywrócone ostrzeżenia, a ostrzeżenia związane z określonymi przypadkami (w tym przypadek domyślny) są teraz wydawane w wierszu zawierającym przypadek naruszenia, a nie w ostatnim wierszu instrukcji switch. W wyniku teraz wydawania tych ostrzeżeń w różnych wierszach niż w przeszłości ostrzeżenia wcześniej pomijane przy użyciu #pragma warning(disable:####) mogą nie być już pomijane zgodnie z oczekiwaniami. Aby pominąć te ostrzeżenia zgodnie z oczekiwaniami, może być konieczne przeniesienie #pragma warning(disable:####) dyrektywy do wiersza powyżej pierwszej sprawy przestępczej. Poniżej przedstawiono przywrócone ostrzeżenia:

    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
    

    Przykład C4063 (przed)

    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;
        }
    };
    

    Przykład C4063 (po)

    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;
        }
    };
    

    Przykłady innych przywróconych ostrzeżeń znajdują się w dokumentacji.

  • #include: używanie specyfikatora katalogu nadrzędnego ".". w nazwa_ścieżki (dotyczy /Wall /WXtylko )

    Poprzednie wersje kompilatora nie wykryły użycia specyfikatora katalogu nadrzędnego ".". w ścieżce #include dyrektyw. Kod napisany w ten sposób jest zwykle przeznaczony do uwzględnienia nagłówków, które istnieją poza projektem, niepoprawnie używając ścieżek względnych projektu. To stare zachowanie spowodowało ryzyko kompilowania programu przez dołączenie innego pliku źródłowego niż zamierzony przez programistę lub że te ścieżki względne nie będą przenośne do innych środowisk kompilacji. Kompilator wykrywa teraz i powiadamia programistę o kodzie napisanym w ten sposób i wyświetla opcjonalne ostrzeżenie kompilatora C4464, jeśli jest włączone.

    warning C4464: relative include path contains '..'
    

    Przykład (przed)

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

    Przykład (po)

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

    Ponadto, mimo że kompilator nie daje określonej diagnostyki, zalecamy również, aby specyfikator katalogu nadrzędnego ".". Nie powinien być używany do określania katalogów dołączania projektu.

  • #pragma optimize() rozszerza poprzedni koniec pliku nagłówka (ma to wpływ tylko na /Wall /WX)

    Poprzednie wersje kompilatora nie wykryły zmian ustawień flag optymalizacji, które unikną pliku nagłówka zawartego w jednostce tłumaczenia. Kompilator wykrywa teraz i powiadamia programistę o kodzie napisanym w ten sposób i wyświetla opcjonalne ostrzeżenie kompilatora C4426 w lokalizacji obiektu, #includejeśli jest włączone. To ostrzeżenie jest wyświetlane tylko wtedy, gdy zmiany powodują konflikt z flagami optymalizacji ustawionymi przez argumenty wiersza polecenia kompilatora.

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

    Przykład (przed)

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

    Przykład (po)

    // 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"
    
  • Niezgodność #pragma warning(push) i ostrzeżenie #pragma (pop) (dotyczy /Wall /WXtylko )

    Poprzednie wersje kompilatora nie wykryły #pragma warning(push) zmian stanu sparowanych ze #pragma warning(pop) zmianami stanu w innym pliku źródłowym, który jest rzadko zamierzony. To stare zachowanie spowodowało ryzyko, że program zostanie skompilowany z innym zestawem ostrzeżeń włączonych niż zamierzony przez programistę, co może spowodować dyskretne złe zachowanie środowiska uruchomieniowego. Kompilator wykrywa teraz i powiadamia programistę o kodzie napisanym w ten sposób i wyświetla opcjonalne ostrzeżenie kompilatora C5031 w lokalizacji pasującego #pragma warning(pop)elementu , jeśli jest włączone. To ostrzeżenie zawiera notatkę odwołującą się do lokalizacji odpowiadającego #pragma warning(push).

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

    Przykład (przed)

    // 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
    ...
    

    Przykład (po)

    // 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"
    ...
    

    Choć nietypowe, kod napisany w ten sposób jest czasami zamierzony. Kod napisany w ten sposób jest wrażliwy na zmiany w #include kolejności. Jeśli to możliwe, zalecamy, aby pliki kodu źródłowego zarządzały stanem ostrzeżenia w sposób samodzielny.

  • Niedopasowane #pragma warning(push) (dotyczy /Wall /WXtylko )

    Poprzednie wersje kompilatora nie wykryły niezgodnych #pragma warning(push) zmian stanu na końcu jednostki tłumaczenia. Kompilator wykrywa teraz i powiadamia programistę o kodzie napisanym w ten sposób i wyświetla opcjonalne ostrzeżenie kompilatora C5032 w lokalizacji niedopasowanego #pragma warning(push)elementu , jeśli jest włączone. To ostrzeżenie jest wyświetlane tylko wtedy, gdy w jednostce tłumaczenia nie występują błędy kompilacji.

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

    Przykład (przed)

    // 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
    

    Przykład (po)

    // 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)
    
  • Dodatkowe ostrzeżenia mogą być wyświetlane w wyniku ulepszonego śledzenia stanu ostrzeżenia #pragma

    Poprzednie wersje kompilatora śledzone #pragma zmiany stanu ostrzeżenia są wystarczająco dobre, aby wyświetlić wszystkie zamierzone ostrzeżenia. To zachowanie spowodowało ryzyko efektywnego pomijania niektórych ostrzeżeń w sytuacjach innych niż zamierzony przez programistę. Kompilator śledzi #pragma warning teraz stan bardziej niezawodnie — szczególnie związane ze #pragma warning zmianami stanu wewnątrz szablonów — i opcjonalnie zgłasza nowe ostrzeżenia C5031 i C5032, które mają pomóc programisty zlokalizować niezamierzone zastosowania #pragma warning(push) elementów i #pragma warning(pop).

    W wyniku ulepszonego #pragma warning śledzenia zmian stanu ostrzeżenia wcześniej nieprawidłowo pominięte lub ostrzeżenia związane z problemami, które były wcześniej błędnie diagnozowane, mogą być teraz wydawane.

  • Ulepszona identyfikacja kodu, który nie jest osiągalny

    Zmiana standardowej biblioteki języka C++ i ulepszona możliwość wbudowanych wywołań funkcji w porównaniu z poprzednimi wersjami kompilatora może pozwolić kompilatorowi udowodnić, że określony kod jest teraz nieosiągalny. To nowe zachowanie może spowodować powstanie nowych i częściej wystawianych wystąpień ostrzeżenia C4720.

    warning C4720: unreachable code
    

    W wielu przypadkach to ostrzeżenie może być wystawiane tylko podczas kompilowania z włączonymi optymalizacjami, ponieważ optymalizacje mogą wstawić więcej wywołań funkcji, wyeliminować nadmiarowy kod lub w inny sposób umożliwić ustalenie, że określony kod jest niemożliwy do osiągnięcia. Zaobserwowaliśmy, że w blokach try/catch często wystąpiły nowe wystąpienia ostrzeżenia C4720, szczególnie w odniesieniu do używania elementu std::find.

    Przykład (przed)

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

    Przykład (po)

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

Ulepszenia zgodności w aktualizacji Update 2

  • Dodatkowe ostrzeżenia i błędy mogą być wystawiane w wyniku częściowej obsługi wyrażenia SFINAE

    Poprzednie wersje kompilatora nie analizuje niektórych rodzajów wyrażeń wewnątrz decltype specyfikatorów z powodu braku obsługi wyrażenia SFINAE. To stare zachowanie było nieprawidłowe i nie jest zgodne ze standardem C++. Kompilator analizuje teraz te wyrażenia i ma częściową obsługę wyrażenia SFINAE ze względu na ciągłe ulepszenia zgodności. W rezultacie kompilator wydaje teraz ostrzeżenia i błędy znalezione w wyrażeniach, które poprzednie wersje kompilatora nie zostały przeanalizowane.

    Gdy to nowe zachowanie analizuje decltype wyrażenie zawierające typ, który nie został jeszcze zadeklarowany, kompilator wystawia błąd kompilatora C2039 w wyniku.

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

    Przykład 1: użycie typu niezadeklarowanego (przed)

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

    Przykład 1 (po)

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

    Gdy to nowe zachowanie analizuje decltype wyrażenie, które nie ma niezbędnego użycia słowa kluczowego typename , aby określić, że nazwa zależna jest typem, kompilator wystawia ostrzeżenie kompilatora C4346 wraz z błędem kompilatora 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'
    

    Przykład 2: nazwa zależna nie jest typem (przed)

    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
    };
    

    Przykład 2 (po)

    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> ()));
    };
    
  • volatileZmienne składowe uniemożliwiają niejawnie zdefiniowane konstruktory i operatory przypisania

    Poprzednie wersje kompilatora zezwalały na klasę, która ma volatile zmienne składowe, aby mieć domyślne konstruktory kopiowania/przenoszenia i automatycznie generowane operatory przypisania kopiowania/przenoszenia. To stare zachowanie było nieprawidłowe i nie jest zgodne ze standardem C++. Kompilator uwzględnia teraz klasę zawierającą zmienne składowe, które mają volatile nietrywialne operatory konstrukcji i przypisania, co uniemożliwia automatyczne generowanie domyślnych implementacji tych operatorów. Gdy taka klasa jest członkiem unii (lub anonimowej unii wewnątrz klasy), konstruktory kopiowania/przenoszenia i operatory przypisania kopiowania/przenoszenia unii (lub klasy zawierającej anonimową unię) będą niejawnie zdefiniowane jako usunięte. Próba skonstruowania lub skopiowania unii (lub klasy zawierającej anonimową unię) bez jawnego zdefiniowania ich jest błędem, a w rezultacie błąd kompilatora problemów kompilatora C2280.

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

    Przykład (przed)

    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
    

    Przykład (po)

    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
    
  • Statyczne funkcje składowe nie obsługują kwalifikatorów cv.

    Poprzednie wersje programu Visual Studio 2015 zezwalały na statyczne funkcje składowe z kwalifikatorami cv. To zachowanie jest spowodowane regresją w programach Visual Studio 2015 i Visual Studio 2015 Update 1; Program Visual Studio 2013 i poprzednie wersje kompilatora odrzucają kod napisany w ten sposób. Zachowanie programów Visual Studio 2015 i Visual Studio 2015 Update 1 jest nieprawidłowe i nie jest zgodne ze standardem C++. Program Visual Studio 2015 Update 2 odrzuca kod napisany w ten sposób i zamiast tego zgłasza błąd kompilatora C2511.

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

    Przykład (przed)

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

    Example(after)

    struct A
    {
        static void func();
    };
    
    void A::func() {}  // removed const
    
  • Przekazywanie deklaracji wyliczenia nie jest dozwolone w kodzie WinRT (dotyczy /ZWtylko )

    Kod skompilowany dla środowisko wykonawcze systemu Windows (WinRT) nie zezwala na enum deklarowanie typów, podobnie jak w przypadku kompilowania zarządzanego kodu C++ dla programu .Net Framework przy użyciu przełącznika kompilatora/clr. To zachowanie gwarantuje, że rozmiar wyliczenia jest zawsze znany i może być poprawnie przewidywany dla systemu typów WinRT. Kompilator odrzuca kod napisany w ten sposób i wystawia błąd kompilatora C2599 wraz z błędem kompilatora C3197.

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

    Przykład (przed)

    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;
        }
    };
    

    Przykład (po)

              // forward declaration of CustomEnum removed
    namespace A {
        public enum class CustomEnum : int32
        {
            Value1
        };
    }
    
    public ref class Component sealed
    {
    public:
        CustomEnum f()
        {
            return CustomEnum::Value1;
        }
    };
    
  • Przeciążony operator nienależące do elementu członkowskiego — nowy, a usuwanie operatora nie może być zadeklarowane w tekście (poziom 1 (/W1) domyślnie)

    Poprzednie wersje kompilatora nie wydają ostrzeżenia, gdy funkcje usuwania operatora innego niż składowe są deklarowane w tekście. Kod napisany w ten sposób jest źle sformułowany (bez wymaganej diagnostyki) i może powodować problemy z pamięcią wynikające z niezgodności nowych i usuniętych operatorów (szczególnie w przypadku użycia razem z przydziałem wielkości), które mogą być trudne do zdiagnozowania. Kompilator wydaje teraz ostrzeżenie kompilatora C4595, aby ułatwić identyfikację kodu napisanego w ten sposób.

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

    Przykład (przed)

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

    Przykład (po)

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

    Naprawienie kodu napisanego w ten sposób może wymagać przeniesienia definicji operatorów z pliku nagłówka i do odpowiedniego pliku źródłowego.

Ulepszenia zgodności w aktualizacji Update 3

  • std::is_convertable wykrywa teraz samodzielne przypisywanie (biblioteka standardowa)

    Poprzednie wersje std::is_convertable cech typu nie wykryły poprawnie samodzielnego przypisania typu klasy, gdy jego konstruktor kopiujący jest usuwany lub prywatny. std::is_convertable<>::value Teraz jest poprawnie ustawiana na false wartość , gdy jest stosowana do typu klasy z usuniętym lub prywatnym konstruktorem kopiowania.

    Brak diagnostyki kompilatora skojarzonej z tą zmianą.

    Przykład

    #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");
    

    W poprzednich wersjach kompilatora statyczne asercji w dolnej części tego przykładu zostały przekazane, ponieważ std::is_convertable<>::value zostały niepoprawnie ustawione na true. std::is_convertable<>::value Teraz jest poprawnie ustawiona na falsewartość , co powoduje niepowodzenie asercji statycznych.

  • Domyślne lub usunięte trywialne kopiowanie i przenoszenie konstruktorów przestrzega specyfikatorów dostępu

    Poprzednie wersje kompilatora nie sprawdzały specyfikatora dostępu domyślnego lub usuniętego trywialnego kopiowania i przenoszenia konstruktorów przed zezwoleniem na ich wywoływanie. To stare zachowanie było nieprawidłowe i nie jest zgodne ze standardem C++. W niektórych przypadkach to stare zachowanie spowodowało ryzyko dyskretnego generowania nieprawidłowego kodu, co spowodowało nieprzewidywalne zachowanie środowiska uruchomieniowego. Kompilator sprawdza teraz specyfikator dostępu domyślnego lub usuniętego trywialnego kopiowania i przenoszenia konstruktorów, aby określić, czy można go wywołać, a jeśli nie, wystawia ostrzeżenie kompilatora C2248 w wyniku.

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

    Przykład (przed)

    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
    }
    

    Przykład (po)

    class S {
    public:
        S() = default;
    private:
        S(const S&) = default;
    };
    
    void f(const S&);  // pass S by reference
    
    int main()
    {
        S s;
        f(s);
    }
    
  • Wycofanie obsługi przypisanych kodów ATL (poziom 1 (/W1) domyślnie)

    Poprzednie wersje kompilatora obsługiwały przypisany kod ATL. W następnej fazie usuwania obsługi przypisanego kodu ATL, który rozpoczął się w programie Visual Studio 2008, przypisany kod ATL został przestarzały. Kompilator wydaje teraz ostrzeżenie kompilatora C4467, aby ułatwić zidentyfikowanie tego rodzaju przestarzałego kodu.

    warning C4467: Usage of ATL attributes is deprecated
    

    Jeśli chcesz nadal używać przypisanego kodu ATL, dopóki obsługa nie zostanie usunięta z kompilatora, możesz wyłączyć to ostrzeżenie, przekazując /Wv:18 argumenty wiersza polecenia lub /wd:4467 do kompilatora lub dodając #pragma warning(disable:4467) kod źródłowy.

    Przykład 1 (przed)

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

    Przykład 1 (po)

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

    Czasami może być konieczne utworzenie lub utworzenie pliku IDL w celu uniknięcia użycia przestarzałych atrybutów ATL, jak w przykładowym kodzie poniżej

    Przykład 2 (przed)

    [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
    {
        // ...
    };
    

    Najpierw utwórz plik *.idl; Wygenerowany plik vc140.idl może służyć do uzyskania pliku *.idl zawierającego interfejsy i adnotacje.

    Następnie dodaj krok MIDL do kompilacji, aby upewnić się, że są generowane definicje interfejsu języka C++.

    Przykład 2 IDL (po)

    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;
    };
    }
    

    Następnie użyj atl bezpośrednio w pliku implementacji, jak w poniższym przykładowym kodzie.

    Przykład 2 Implementacja (po)

    #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()
    };
    
  • Wstępnie skompilowane pliki nagłówka (PCH) i niedopasowane dyrektywy #include (mają wpływ tylko na /Wall /WX)

    Poprzednie wersje kompilatora zaakceptowały #include niezgodność dyrektyw w plikach źródłowych między kompilacjami -Yc i -Yu podczas używania plików prekompilowanego nagłówka (PCH). Kod napisany w ten sposób nie jest już akceptowany przez kompilator. Kompilator wydaje teraz ostrzeżenie kompilatora CC4598, aby ułatwić identyfikowanie niezgodnych #include dyrektyw podczas korzystania z plików PCH.

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

    Przykład (przed):

    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"
    

    Przykład (po)

    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"
    
  • Wstępnie skompilowane pliki nagłówka (PCH) i niedopasowane katalogi dołączania (dotyczy /Wall /WXtylko )

    Poprzednie wersje kompilatora zaakceptowały niezgodność argumentów wiersza polecenia dołączania () katalogu (-I) do kompilatora między kompilacjami -Yc i -Yu podczas używania plików prekompilowanego nagłówka (PCH). Kod napisany w ten sposób nie jest już akceptowany przez kompilator. Kompilator wydaje teraz ostrzeżenie kompilatora CC4599, aby ułatwić identyfikację niezgodnych argumentów wiersza polecenia dołączania katalogu (-I) podczas korzystania z plików PCH.

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

    Przykład (przed)

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

    Przykład (po)

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

Zmiany zgodności programu Visual Studio 2013

Compiler

  • Ostatnie słowo kluczowe generuje teraz nierozwiązany błąd symbolu, w którym zostałby skompilowany wcześniej:

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

    We wcześniejszych wersjach błąd nie został wystawiony, ponieważ wywołanie było wywołaniem virtual , mimo to program ulegał awarii w czasie wykonywania. Teraz zostaje zgłoszony błąd konsolidatora, ponieważ wiadomo, że klasa jest ostateczna. W tym przykładzie, aby naprawić błąd, należy połączyć się z obj zawierającym definicję S2::f.

  • W przypadku korzystania z funkcji zaprzyjaźnionych w przestrzeniach nazw należy ponownie zadeklarować funkcję znajomą przed jej odwołaniem lub zostanie wyświetlony błąd, ponieważ kompilator jest teraz zgodny ze standardem ISO C++. Na przykład ten przykład nie jest już kompilowany:

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

    Aby poprawić ten kod, zadeklaruj friend funkcję:

    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);
        }
    
  • Język C++ Standard nie zezwala na jawną specjalizację w klasie. Mimo że kompilator języka Microsoft C++ pozwala na to w niektórych przypadkach, w takich przypadkach, w takich jak poniższy przykład, zostanie wygenerowany błąd, ponieważ kompilator nie uwzględnia drugiej funkcji jako specjalizacji pierwszego.

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

    Aby poprawić ten kod, zmodyfikuj drugą funkcję:

    template <> void f(char& val);
    
  • Kompilator nie próbuje już uściślać dwóch funkcji w poniższym przykładzie, a teraz emituje błąd:

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

    Aby poprawić ten kod, wyjaśnij wywołanie:

    template< typename T> void Func(T* t = nullptr);
    template< typename T> void Func(...);
    
    int main() {
        Func< int>(nullptr); // ok
    }
    
  • Zanim kompilator jest zgodny z normą ISO C++11, skompilowałby następujący kod i spowodował x rozwiązanie problemu z typem int:

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

    Ten kod jest teraz rozpoznawany x jako typ std::initializer_list<int> i powoduje błąd w następnym wierszu, który próbuje przypisać x do typu int. (Domyślnie nie ma konwersji). Aby poprawić ten kod, użyj polecenia , aby zastąpić autoelement int :

    int x = {0};
    int y = x;
    
  • Inicjowanie agregacji nie jest już dozwolone, gdy typ wartości po prawej stronie nie jest zgodny z typem inicjowanej wartości po lewej stronie, a błąd jest wyświetlany, ponieważ standard ISO C++11 wymaga jednolitej inicjalizacji do pracy bez zawężenia konwersji. Wcześniej, jeśli dostępna była konwersja zawężania, ostrzeżenie kompilatora (poziom 4) C4242 zostałoby wydane zamiast błędu.

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

    Aby poprawić ten kod, dodaj jawną konwersję zawężającą:

    int i = 0;
    char c = {static_cast<char>(i)};
    
  • Następujące inicjowanie nie jest już dozwolone:

    void *p = {{0}};
    

    Aby poprawić ten kod, użyj którejś z tych postaci:

    void *p = 0;
    // or
    void *p = {0};
    
  • Wyszukiwanie nazw zostało zmienione. Poniższy kod jest rozpoznawany inaczej w kompilatorze języka C++ w programach Visual Studio 2012 i Visual Studio 2013:

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

    W programie Visual Studio 2012 E1 wyrażenie E1::b in rozpoznane jako ::E1 w zakresie globalnym. W programie Visual Studio 2013 E1 wyrażenie E1::b jest rozpoznawane jako typedef E2 definicja w main() pliku i ma typ ::E2.

  • Układ obiektu został zmieniony. W x64, układ obiektu klasy może się zmienić w porównaniu z poprzednimi wydaniami. Jeśli ma virtual funkcję, ale nie ma klasy bazowej, która ma virtual funkcję, model obiektów kompilatora wstawia wskaźnik do virtual tabeli funkcji po układzie składowym danych. Oznacza to, że układ może nie być optymalny we wszystkich przypadkach. W poprzednich wersjach optymalizacja dla x64 próbowała ulepszyć układ, ale ponieważ nie działa prawidłowo w złożonych sytuacjach kodu, została usunięta w programie Visual Studio 2013. Na przykład, rozważmy ten kod:

    __declspec(align(16)) struct S1 {
    };
    
    struct S2 {
        virtual ~S2();
        void *p;
        S1 s;
    };
    
  • W programie Visual Studio 2013 wynik sizeof(S2) w wersji x64 wynosi 48, ale w poprzednich wersjach daje 32. Aby wykonać tę ocenę do 32 w kompilatorze języka C++ programu Visual Studio 2013 dla x64, dodaj fikcyjną klasę bazową virtual , która ma funkcję:

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

    Aby znaleźć miejsca w kodzie, które wcześniejsza wersja próbowałaby zoptymalizować, użyj kompilatora z tej wersji wraz z opcją kompilatora /W3 i włącz ostrzeżenie C4370. Na przykład:

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

    Przed programem Visual Studio 2013 ten kod zwraca następujący komunikat: "ostrzeżenie C4370: "S2" : układ klasy został zmieniony z poprzedniej wersji kompilatora z powodu lepszego pakowania".

    Kompilator x86 ma ten sam nieoptymalny problem z układem we wszystkich wersjach kompilatora. Na przykład, jeśli ten kod jest kompilowany dla architektury x86:

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

    Wynik sizeof(S) wynosi 24. Można go jednak zmniejszyć do 16, jeśli użyjesz obejścia wymienionego dla x64:

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

Standardowa biblioteka

Kompilator języka C++ w programie Visual Studio 2013 wykrywa niezgodność w _ITERATOR_DEBUG_LEVEL, który został zaimplementowany w programie Visual Studio 2010 i niezgodności środowiska RuntimeLibrary. Te niezgodności występują, gdy opcje /MT kompilatora (wersja statyczna), /MTd (debugowanie statyczne), /MD (wersja dynamiczna) i /MDd (debugowanie dynamiczne) są mieszane.

  • Jeśli kod potwierdzi symulowane szablony aliasów poprzedniej wersji, musisz go zmienić. Na przykład zamiast allocator_traits<A>::rebind_alloc<U>::other, teraz musisz powiedzieć allocator_traits<A>::rebind_alloc<U>. Mimo ratio_add<R1, R2>::type że nie jest już konieczne i teraz zalecamy, aby powiedzieć ratio_add<R1, R2>, pierwszy będzie nadal kompilowany, ponieważ ratio<N, D> jest wymagany do "typu" typedef dla zmniejszonego współczynnika, który będzie tego samego typu, jeśli jest już zmniejszony.

  • Należy użyć #include <algorithm> podczas wywoływania polecenia std::min() lub std::max().

  • Jeśli istniejący kod używa symulowanych wyliczenia w zakresie poprzedniej wersji — tradycyjnych wyliczenia niezakresowe opakowane w przestrzenie nazw — musisz go zmienić. Jeśli na przykład odwołujesz się do typu std::future_status::future_status, teraz musisz powiedzieć std::future_status. Jednak większość kodu nie ma wpływu — na przykład std::future_status::ready nadal kompiluje się.

  • explicit operator bool() jest bardziej rygorystyczny niż operator nieokreślony-bool-type(). explicit operator bool() zezwala na jawne konwersje na wartość logiczną — na przykład podane shared_ptr<X> spwartości , i static_cast<bool>(sp) bool b(sp) są prawidłowe — oraz warunkowe "konwersje kontekstowe" na wartość logiczną — na przykład if (sp), !sp, sp && niezależnie od tego. explicit operator bool() Jednak zabrania niejawnych konwersji na wartość logiczną, więc nie można powiedzieć bool b = sp; i podanego typu zwracanego wartości logicznej, nie można powiedzieć return sp.

  • Teraz, gdy prawdziwe szablony wariadyczne są implementowane, _VARIADIC_MAX i powiązane makra nie mają efektu. Jeśli nadal definiujesz _VARIADIC_MAX, jest on ignorowany. Jeśli przyjmiesz nasze rozwiązania makr przeznaczone do wspierania symulowanych szablonów wariadycznych w jakikolwiek inny sposób, musisz zmienić kod.

  • Oprócz zwykłych słów kluczowych nagłówki standardowej biblioteki języka C++ zabraniają teraz zastępowania makra słowami kluczowymi kontekstowymi i końcowymi.

  • reference_wrapper, ref()i cref() teraz zabrania powiązania z obiektami tymczasowymi.

  • <random> teraz ściśle wymusza warunki wstępne kompilowania.

  • Różne cechy typu standardowej biblioteki języka C++ mają warunek wstępny "T musi być kompletnym typem". Mimo że kompilator wymusza teraz ten warunek wstępny bardziej ściśle, może nie wymuszać go we wszystkich sytuacjach. (Ponieważ naruszenia warunków wstępnych biblioteki standardowej języka C++ wyzwalają niezdefiniowane zachowanie, standard nie gwarantuje wymuszania).

  • Biblioteka Standardowa języka C++ nie obsługuje programu /clr:oldSyntax.

  • Specyfikacja języka C++11 dla common_type<> nieoczekiwanych i niepożądanych konsekwencji, w szczególności zwraca common_type<int, int>::type wartość int&&. W związku z tym kompilator implementuje proponowane rozwiązanie problemu grupy roboczej biblioteki 2141, co zwraca common_type<int, int="">::type wartość int.

    Jako efekt uboczny tej zmiany przypadek tożsamości nie działa już (common_type<T> nie zawsze powoduje typ T). To zachowanie jest zgodne z proponowanym rozwiązaniem, ale powoduje uszkodzenie kodu, który polegał na poprzednim zachowaniu.

    Jeśli potrzebujesz cech typu tożsamości, nie używaj standardu std::identity zdefiniowanego w <type_traits> programie , ponieważ nie będzie działać dla elementu <void>. Zamiast tego wdróż własną cechę typu tożsamości odpowiednią do własnych potrzeb. Oto przykład:

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

MFC i ATL

  • Tylko program Visual Studio 2013: biblioteka MFC MBCS nie jest uwzględniona w programie Visual Studio, ponieważ Standard Unicode jest tak popularny, a użycie MBCS znacznie spadło. Ta zmiana podtrzymuje również ściślejszą relację między MFC a Windows SDK. ponieważ wiele nowych kontrolek i komunikatów wymaga Unicode. Jeśli jednak musisz nadal korzystać z biblioteki MFC MBCS, możesz pobrać ją z Centrum pobierania Microsoft w bibliotece MFC Multibyte dla programu Visual Studio 2013. Pakiet redystrybucyjny Visual C++ wciąż zawiera tę bibliotekę. (Uwaga: biblioteka DLL MBCS jest zawarta w składnikach instalacyjnych języka C++ w programie Visual Studio 2015 lub nowszym).

  • Ułatwienia dostępu dla wstążki MFC są zmieniane. Zamiast architektury jednowarstwowej istnieje teraz architektura hierarchiczna. Nadal możesz użyć starego zachowania, wywołując polecenie CRibbonBar::EnableSingleLevelAccessibilityMode().

  • CDatabase::GetConnect Metoda jest usuwana. Aby zwiększyć bezpieczeństwo, parametry połączenia jest teraz przechowywany w postaci zaszyfrowanej i jest odszyfrowywana tylko w razie potrzeby; nie można jej zwracać jako zwykłego tekstu. Ciąg można uzyskać przy użyciu CDatabase::Dump metody .

  • CWnd::OnPowerBroadcast Podpis jest zmieniany. Sygnatura tego programu obsługi komunikatu została zmieniona, aby przyjąć LPARAM jako drugi parametr.

  • Podpisy są zmieniane tak, aby obsługiwały programy obsługi komunikatów. Listy parametrów dla poniższych funkcji zostały zmienione, aby używać nowo dodanych programów obsługi komunikatów ON_WM_*:

    • CWnd::OnDisplayChange zmieniono na (UINT, int, int) zamiast (WPARAM, LPARAM), aby nowe makro ON_WM_DISPLAYCHANGE można było używać na mapie komunikatów.

    • CFrameWnd::OnDDEInitiate zmieniono wartość na (CWnd*, UINT, UNIT) zamiast (WPARAM, LPARAM), aby nowe makro ON_WM_DDE_INITIATE można było używać na mapie komunikatów.

    • CFrameWnd::OnDDEExecute zmieniono wartość na (CWnd*, HANDLE) zamiast (WPARAM, LPARAM), aby nowe makro ON_WM_DDE_EXECUTE można było używać na mapie komunikatów.

    • CFrameWnd::OnDDETerminate zmieniono wartość na (CWnd*) jako parametr zamiast (WPARAM, LPARAM), aby nowe makro ON_WM_DDE_TERMINATE można było użyć na mapie komunikatów.

    • CMFCMaskedEdit::OnCut zmieniono wartość na brak parametrów zamiast (WPARAM, LPARAM), aby nowe makro ON_WM_CUT można było używać na mapie komunikatów.

    • CMFCMaskedEdit::OnClear zmieniono wartość na brak parametrów zamiast (WPARAM, LPARAM), aby nowe makro ON_WM_CLEAR można było używać na mapie komunikatów.

    • CMFCMaskedEdit::OnPaste zmieniono wartość na brak parametrów zamiast (WPARAM, LPARAM), aby nowe makro ON_WM_PASTE można było używać na mapie komunikatów.

  • #ifdef dyrektywy w plikach nagłówków MFC są usuwane. Usunięto wiele #ifdef dyrektyw w plikach nagłówków MFC powiązanych z nieobsługiwaną wersją systemu Windows (WINVER < 0x0501).

  • Biblioteka DLL ATL (atl120.dll) jest usuwana. ATL jest obecnie dostarczany jako nagłówki i biblioteka statyczna (atls.lib).

  • Usunięto bibliotekę Atlsd.lib, atlsn.lib i atlsnd.lib. Atls.lib nie ma już zależności zestawu znaków ani kodu, który jest specyficzny dla wersji do debugowania/oficjalnych. Ponieważ działa tak samo dla Unicode/ANSI i wersji do debugowania/oficjalnych, wymagana jest tylko jedna wersja biblioteki.

  • Narzędzie śledzenia ATL/MFC jest usuwane wraz z biblioteką DLL ATL, a mechanizm śledzenia jest uproszczony. Konstruktor CTraceCategory przyjmuje teraz jeden parametr (nazwę kategorii), a makra TRACE nazywają funkcje raportowania debugowania CRT.

Zmiany powodujące niezgodność programu Visual Studio 2012

Compiler

  • Opcja kompilatora została zmieniona /Yl . Domyślnie kompilator używa tej opcji, co może prowadzić do LNK2011 błędów w określonych warunkach. Aby uzyskać więcej informacji, zobacz /Yl (Wstrzykiwanie odwołania PCH do biblioteki debugowania).

  • W kodzie skompilowanym przy użyciu metody /clrenum słowo kluczowe klasy definiuje wyliczenie języka C++11, a nie wyliczenie środowiska uruchomieniowego języka wspólnego (CLR). Aby zdefiniować wyliczenie CLR, należy jawnie określić jego dostępność.

  • Użyj słowa kluczowego szablonu, aby jawnie uściślić nazwę zależną (zgodność ze standardem języka C++). W poniższym przykładzie wyróżnione słowo kluczowe szablonu jest obowiązkowe, aby rozwiązać niejednoznaczność. Aby uzyskać więcej informacji, zobacz Rozpoznawanie nazw dla typów zależnych.

    template < typename X = "", typename = "" AY = "">
    struct Container { typedef typename AY::template Rebind< X> ::Other AX; };
    
  • Stałe wyrażenie typu float nie jest już dozwolone jako argument szablonu, jak pokazano w poniższym przykładzie.

    template<float n=3.14>
    struct B {};  // error C2993: 'float': illegal type for non-type template parameter 'n'
    
  • Kod, który jest kompilowany przy użyciu /GS opcji wiersza polecenia i który ma lukę w zabezpieczeniach poza jednym może prowadzić do zakończenia procesu w czasie wykonywania, jak pokazano w poniższym przykładzie pseudokodu.

    char buf[MAX]; int cch; ManipulateString(buf, &cch); // ... buf[cch] = '\0'; // if cch >= MAX, process will terminate
    
  • Domyślna architektura kompilacji x86 została zmieniona na SSE2; dlatego kompilator może emitować instrukcje SSE i będzie używać rejestrów XMM do wykonywania obliczeń zmiennoprzecinkowych. Jeśli chcesz przywrócić poprzednie zachowanie, użyj /arch:IA32 flagi kompilatora, aby określić architekturę jako IA32.

  • Kompilator może wystawiać ostrzeżenia kompilatora Ostrzeżenie (poziom 4) C4703 i C4701, gdzie wcześniej tego nie zrobił. Kompilator stosuje silniejsze kontrole użycia niezainicjowanych zmiennych lokalnych typu wskaźnika.

  • Po określeniu nowej flagi /HIGHENTROPYVA konsolidatora system Windows 8 zwykle powoduje, że alokacje pamięci zwracają adres 64-bitowy. (Przed systemem Windows 8 takie alokacje częściej zwracały adresy, które były mniejsze niż 2 GB). Ta zmiana może spowodować uwidocznienie usterek obcięcia wskaźnika w istniejącym kodzie. Domyślnie ten przełącznik jest włączony. Aby wyłączyć to zachowanie, określ wartość /HIGHENTROPYVA:NO.

  • Zarządzany kompilator (Visual Basic/C#) obsługuje /HIGHENTROPYVA również kompilacje zarządzane. Jednak w tym przypadku właściwość /HIGHENTROPYVAswitch jest domyślnie wyłączona.

IDE

  • Chociaż zalecamy, aby nie tworzyć aplikacji Windows Forms w języku C++/CLI, obsługiwana jest konserwacja istniejących aplikacji interfejsu użytkownika języka C++/CLI. Jeśli musisz utworzyć aplikację Windows Forms lub inną aplikację interfejsu użytkownika platformy .NET, użyj języka C# lub Visual Basic. Używaj języka C++/interfejsu wiersza polecenia tylko do celów współdziałania.

Biblioteka wzorców równoległych i biblioteka środowiska uruchomieniowego współbieżności

Wyliczenie SchedulerType elementu UmsThreadDefault jest przestarzałe. UmsThreadDefault Specyfikacja generuje przestarzałe ostrzeżenie i wewnętrznie mapuje z powrotem na ThreadScheduler.

Standardowa biblioteka

  • Po zmianie powodującej niezgodność między standardami C++98/03 i C++11 używanie jawnych argumentów szablonu do wywoływania make_pair() — tak jak w make_pair<int, int>(x, y) przypadku — zwykle nie kompiluje się w programie Visual C++ w programie Visual Studio 2012. Rozwiązaniem jest zawsze wywoływanie make_pair() bez jawnych argumentów szablonu — tak jak w pliku make_pair(x, y). Podanie jawnych argumentów szablonu pokonuje przeznaczenie funkcji. Jeśli potrzebujesz dokładnej kontroli nad typem wynikowym, użyj polecenia pair zamiast make_pair — jak w pliku pair<short, short>(int1, int2).

  • Kolejna zmiana powodująca niezgodność między standardami C++98/03 i C++11: Gdy A jest niejawnie konwertowana na B i B, jest niejawnie konwertowana na język C, ale A nie jest niejawnie konwertowana na C, C++98/03 i Visual Studio 2010, które mogą być konwertowane pair<A, X> (niejawnie lub jawnie) na pair<C, X>. (Inny typ, X, nie jest tutaj interesujący i nie jest specyficzny dla pierwszego typu w parze). Kompilator języka C++ w programie Visual Studio 2012 wykrywa, że element A nie jest niejawnie konwertowany na język C i usuwa konwersję pary z rozpoznawania przeciążeń. Ta zmiana jest pozytywna dla wielu scenariuszy. Na przykład przeciążenie i func(const pair<string, string>&)wywołanie pair<const char *, const char *> func(const pair<int, int>&) func() polecenia za pomocą polecenia skompiluje się z tą zmianą. Jednak ta zmiana powoduje przerwanie kodu, który polegał na agresywnych konwersjach par. Taki kod można zwykle naprawić, wykonując jedną część konwersji jawnie — na przykład przekazując make_pair(static_cast<B>(a), x) do funkcji, która oczekuje pair<C, X>.

  • Symulowane szablony variadzkie programu Visual Studio 2010 — na przykład make_shared<T>(arg1, arg2, argN)— do limitu 10 argumentów przez wykorzeczenie przeciążeń i specjalizacji z maszynami preprocesorowymi. W programie Visual Studio 2012 ten limit jest ograniczony do pięciu argumentów, aby skrócić czas kompilacji i zużycie pamięci kompilatora dla większości użytkowników. Można jednak ustawić poprzedni limit, jawnie definiując _VARIADIC_MAX jako 10 dla całego projektu.

  • C++11 17.6.4.3.1 [macro.names]/2 zabrania zamiany makra słów kluczowych, gdy dołączane są nagłówki standardowej biblioteki języka C++. Nagłówki emitują teraz błędy kompilatora, jeśli wykrywają słowa kluczowe zastąpione makrami. (Definiowanie _ALLOW_KEYWORD_MACROS umożliwia kompilowanie takiego kodu, ale zdecydowanie odradzamy to użycie). Wyjątkiem jest to, że forma new makra jest domyślnie dozwolona, ponieważ nagłówki są kompleksowo bronione za pomocą polecenia/#pragma push_macro("new")#undef new/#pragma pop_macro("new") . Definiowanie _ENFORCE_BAN_OF_MACRO_NEW dokładnie określa jego nazwę.

  • Aby zaimplementować różne optymalizacje i testy debugowania, implementacja standardowej biblioteki C++ celowo przerywa zgodność binarną między wersjami programu Visual Studio (2005, 2008, 2010, 2012). Gdy używana jest standardowa biblioteka języka C++, zabrania mieszania plików obiektów i bibliotek statycznych kompilowanych przy użyciu różnych wersji w jednym pliku binarnym (EXE lub DLL) i zabrania przekazywania obiektów biblioteki standardowej języka C++ między plikami binarnymi kompilowanymi przy użyciu różnych wersji. Mieszanie plików obiektów i bibliotek statycznych (przy użyciu standardowej biblioteki języka C++ skompilowanej przy użyciu programu Visual Studio 2010 z plikami skompilowanymi przy użyciu kompilatora C++ w programie Visual Studio 2012 emituje błędy konsolidatora dotyczące niezgodności _MSC_VER, gdzie _MSC_VER jest makro zawierające wersję główną kompilatora (1700 dla języka Visual C++ w programie Visual Studio 2012). To sprawdzenie nie może wykryć mieszania bibliotek DLL i nie może wykryć mieszania, które obejmuje program Visual Studio 2008 lub starszy.

  • Oprócz wykrywania niezgodności _ITERATOR_DEBUG_LEVEL, które zostały zaimplementowane w programie Visual Studio 2010, kompilator języka C++ w programie Visual Studio 2012 wykrywa niezgodność bibliotek środowiska uruchomieniowego. Te niezgodności występują, gdy opcje /MT kompilatora (wersja statyczna), /MTd (debugowanie statyczne), /MD (wersja dynamiczna) i /MDd (debugowanie dynamiczne) są mieszane.

  • operator<(), , operator>()operator<=()i operator>=() były wcześniej dostępne dla std::unordered_map rodzin kontenerów istdext::hash_map, chociaż ich implementacje nie były przydatne. Te nietypowe operatory zostały usunięte w programie Visual C++ w programie Visual Studio 2012. Ponadto wdrożenie operator==() i operator!=() dla std::unordered_map rodziny zostało rozszerzone o pokrycie stdext::hash_map rodziny. (Zalecamy unikanie używania stdext::hash_map rodziny w nowym kodzie).

  • C++11 22.4.1.4 [locale.codecvt] określa, że codecvt::length() i codecvt::do_length() powinien przyjmować modyfikowalne stateT& parametry, ale program Visual Studio 2010 wziął wartość const stateT&. Kompilator języka C++ w programie Visual Studio 2012 jest stateT& wymagany przez standard. Ta różnica jest znacząca dla każdego, kto próbuje zastąpić funkcję do_length()wirtualną .

CRT

  • Sterta C Runtime (CRT), która jest używana dla nowych i malloc(), nie jest już prywatna. CRT używa teraz sterty procesu. Oznacza to, że sterta nie zostanie zniszczona, gdy biblioteka DLL zostanie zwolniona, dlatego biblioteki DLL, które statycznie łączą się ze statycznie z CRT, muszą zapewnić, że pamięć przydzielona przez kod DLL zostanie wyczyszczona przed jego zwolnieniem.

  • Funkcja iscsymf() jest asercyjna z wartościami ujemnymi.

  • Struktura została zmieniona threadlocaleinfostruct , aby uwzględnić zmiany w funkcjach ustawień regionalnych.

  • Funkcje CRT, które mają odpowiednie funkcje wewnętrzne, takie jak memxxx(), strxxx() są usuwane z intrin.h. Jeśli dołączono tylko intrin.h tylko dla tych funkcji, musisz teraz dołączyć odpowiednie nagłówki CRT.

MFC i ATL

  • Usunięto obsługę łączenia (afxcomctl32.h); w związku z tym wszystkie metody zdefiniowane w zostały <afxcomctl32.h> usunięte. Pliki <afxcomctl32.h> nagłówka i <afxcomctl32.inl> zostały usunięte.

  • Zmieniono nazwę na CDockablePane::RemoveFromDefaultPaneDividier CDockablePane::RemoveFromDefaultPaneDivider.

  • Zmieniono podpis funkcji LPCTSTR, w związku z CFileDialog::SetDefExt czym mają wpływ kompilacje Unicode.

  • Usunięto przestarzałe kategorie śledzenia ATL.

  • Zmieniono podpis , CBasePane::MoveWindow aby wykonać polecenie const CRect.

  • Zmieniono podpis .CMFCEditBrowseCtrl::EnableBrowseButton

  • Usunięto właściwości m_fntTabs i m_fntTabsBold z klasy CMFCBaseTabCtrl.

  • Dodano parametr do CMFCRibbonStatusBarPane konstruktorów. (Jest to parametr domyślny, więc nie jest to przerywanie źródła).

  • Dodano parametr do konstruktora CMFCRibbonCommandsListBox . (Jest to parametr domyślny, więc nie jest to przerywanie źródła).

  • Usunięto AFXTrackMouse interfejs API (i powiązany czasomierz proc). Zamiast tego użyj interfejsu API Win32 TrackMouseEvent .

  • Dodano parametr do konstruktora CFolderPickerDialog . (Jest to parametr domyślny, więc nie jest to przerywanie źródła).

  • CFileStatus zmieniono rozmiar struktury: m_attribute element członkowski zmienił się z BYTE na DWORD (aby był zgodny z wartością zwróconą z GetFileAttributes).

  • CRichEditCtrl i CRichEditView używaj MSFTEDIT_CLASS (kontrolka RichEdit 4.1) zamiast RICHEDIT_CLASS (kontrolka RichEdit 3.0) w kompilacjach Unicode.

  • Usunięto AFX_GLOBAL_DATA::IsWindowsThemingDrawParentBackground , ponieważ jest to zawsze prawda w systemach Windows Vista, Windows 7 i Windows 8.

  • Usunięto AFX_GLOBAL_DATA::IsWindowsLayerSupportAvailable , ponieważ jest to zawsze prawda w systemach Windows Vista, Windows 7 i Windows 8.

  • Usunięto AFX_GLOBAL_DATA::DwmExtendFrameIntoClientAreaelement . Wywoływanie interfejsu API systemu Windows bezpośrednio w systemach Windows Vista, Windows 7 i Windows 8.

  • Usunięto AFX_GLOBAL_DATA::DwmDefWindowProcelement . Wywoływanie interfejsu API systemu Windows bezpośrednio w systemach Windows Vista, Windows 7 i Windows 8.

  • Zmieniono AFX_GLOBAL_DATA::DwmIsCompositionEnabled nazwę na , aby IsDwmCompositionEnabled wyeliminować kolizję nazw.

  • Zmieniono identyfikatory dla kilku wewnętrznych czasomierzy MFC i przeniesiono definicje do afxres.h (AFX_TIMER_ID_*).

  • Zmieniono podpis OnExitSizeMove metody tak, aby zgodziła się z makrem ON_WM_EXITSIZEMOVE:

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

  • Zmieniono nazwę i podpis OnDWMCompositionChanged , aby wyrazić zgodę na makro ON_WM_DWMCOMPOSITIONCHANGED:

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

  • Zmieniono podpis OnMouseLeave metody tak, aby zgodziła się z makrem ON_WM_MOUSELEAVE:

    • CMFCCaptionBar

    • CMFCColorBar

    • CMFCHeaderCtrl

    • CMFCProperySheetListBox

    • CMFCRibbonBar

    • CMFCRibbonPanelMenuBar

    • CMFCRibbonRichEditCtrl

    • CMFCSpinButtonCtrl

    • CMFCToolBar ReplaceThisText

    • CMFCToolBarComboBoxEdit

    • CMFCToolBarEditCtrl

    • CMFCAutoHideBar

  • Zmieniono podpis OnPowerBroadcast , aby zaakceptować makro ON_WM_POWERBROADCAST:

    • CFrameWndEx

    • CMDIFrameWndEx

  • Zmieniono podpis OnStyleChanged w celu zaakceptowania makra ON_WM_STYLECHANGED:

    • CMFCListCtrl

    • CMFCStatusBar

  • Zmieniono nazwę metody FontFamalyProcFonts wewnętrznej na FontFamilyProcFonts.

  • Usunięto wiele globalnych obiektów statycznych CString , aby wyeliminować przecieki pamięci w niektórych sytuacjach (zastąpione #defines) oraz następujące zmienne składowe klasy:

    • 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

  • Zmieniono podpis i CKeyboardManager::ShowAllAccelerators usunięto parametr ogranicznika akceleratora.

  • Dodano CPropertyPage::GetParentSheetelement , i w CPropertyPage klasie wywołaj ją zamiast GetParent , aby uzyskać poprawne okno arkusza nadrzędnego, które może być oknem rodzica lub dziadka do CPropertyPage. Może być konieczne zmianę kodu w celu wywołania GetParentSheet metody zamiast GetParent.

  • Naprawiono niezrównoważone ostrzeżenie (wypychanie) #pragma w usłudze ATLBASE. H, co spowodowało nieprawidłowe wyłączenie ostrzeżeń. Ostrzeżenia te są teraz poprawnie włączone po atLBASE. H został przeanalizowany.

  • Przeniesiono metody związane z D2D z AFX_GLOBAL_DATA do _AFX_D2D_STATE:

    • GetDirectD2dFactory

    • GetWriteFactory

    • GetWICFactory

    • InitD2D

    • ReleaseD2DRefs

    • IsD2DInitialized

    • D2D1MakeRotateMatrix

    • Zamiast wywoływać, na przykład , afxGlobalData.IsD2DInitializedwywołaj metodę AfxGetD2DState->IsD2DInitialized.

  • Usunięto przestarzałe atl*. Pliki CPP z folderu \atlmfc\include\.

  • Przeniesiono afxGlobalData inicjowanie na żądanie zamiast w czasie inicjowania CRT, aby spełnić DLLMain wymagania.

  • Dodano metodę RemoveButtonByIndex CMFCOutlookBarPane do klasy .

  • Poprawiono CMFCCmdUsageCount::IsFreqeuntlyUsedCmd do IsFrequentlyUsedCmd.

  • Poprawiono kilka wystąpień elementu RestoreOriginalstate do RestoreOriginalState (CMFCToolBar, CMFCMenuBar, CMFCOutlookBarPane).

  • Usunięto nieużywane metody z CDockablePane: SetCaptionStyle, , IsDrawCaptionIsHideDisabledButtons, GetRecentSiblingPaneInfoi CanAdjustLayout.

  • Usunięto CDockablePane statyczne zmienne m_bCaptionText składowe i m_bHideDisabledButtons.

  • Dodano metodę zastąpienia DeleteString do CMFCFontComboBoxmetody .

  • Usunięto nieużywane metody z CPaneklasy : GetMinLength i IsLastPaneOnLastRow.

  • Zmieniono CPane::GetDockSiteRow(CDockingPanesRow *) nazwę na CPane::SetDockSiteRow.

Zmiany powodujące niezgodność programu Visual Studio 2010

Compiler

  • Słowo auto kluczowe ma nowe znaczenie domyślne. Ponieważ użycie starego znaczenia jest rzadkie, większość aplikacji nie będzie miała wpływu na tę zmianę.

  • static_assert Nowe słowo kluczowe zostanie wprowadzone, co spowoduje konflikt nazw, jeśli w kodzie istnieje już identyfikator o tej nazwie.

  • Obsługa nowej notacji lambda wyklucza obsługę kodowania niekwestionowanego identyfikatora GUID w atrybucie UUID języka IDL.

  • Program .NET Framework 4 wprowadza koncepcję uszkodzonych wyjątków stanu, które są wyjątkami, które pozostawiają proces w nieodwracalnym stanie uszkodzonym. Domyślnie nie można przechwycić uszkodzonego wyjątku stanu, nawet w przypadku opcji kompilatora /EHa, która przechwytuje wszystkie inne wyjątki. Aby jawnie przechwycić uszkodzony wyjątek stanu, użyj instrukcji __try-__except. Możesz też zastosować atrybut [HandledProcessCorruptedStateExceptions], aby umożliwić funkcji przechwytywanie uszkodzonych wyjątków stanu. Ta zmiana dotyczy głównie programistów systemowych, którzy mogą mieć możliwość przechwycenia uszkodzonego wyjątku stanu. Osiem wyjątków to 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. Aby uzyskać więcej informacji na temat tych wyjątków, zobacz makro GetExceptionCode .

  • Poprawiona /GS opcja kompilatora chroni przed przekroczeniem buforu bardziej kompleksowo niż we wcześniejszych wersjach. Ta wersja może wstawić dodatkowe kontrole zabezpieczeń w stosie, który może zmniejszyć wydajność. Użyj nowego __declspec(safebuffers) słowa kluczowego, aby poinstruować kompilatora, aby nie wstawiał kontroli zabezpieczeń dla określonej funkcji.

  • Jeśli kompilujesz zarówno opcje kompilatora /GL (Optymalizacja całego programu) i /clr (kompilacja /GL środowiska uruchomieniowego języka wspólnego), opcja zostanie zignorowana. Ta zmiana została wprowadzona, ponieważ kombinacja opcji kompilatora przyniosła niewielkie korzyści. W wyniku tej zmiany wydajność kompilacji zostanie zwiększona.

  • Domyślnie obsługa trigrafów jest wyłączona w programie Visual Studio 2010. Użyj opcji kompilatora /Zc:trigraphs , aby włączyć obsługę trigrafów. Trójznak składa się z dwóch kolejnych znaków zapytania ("??"), po których następuje unikatowy trzeci znak. Kompilator zastępuje trigraf odpowiednim znakiem interpunkcyjnym. Na przykład kompilator zastępuje ??= trigraf znakiem "#". Użyj trigrafów w plikach źródłowych języka C, które używają zestawu znaków, który nie zawiera wygodnych reprezentacji graficznych dla niektórych znaków interpunkcyjnych.

  • Konsolidator nie obsługuje już optymalizacji pod kątem systemu Windows 98. Opcja /OPT (Optymalizacje) generuje błąd czasu kompilacji, jeśli określisz /OPT:WIN98 wartość lub /OPT:NOWIN98.

  • Domyślne opcje kompilatora określone przez właściwości systemu kompilacji RuntimeLibrary i DebugInformationFormat zostały zmienione. Domyślnie te właściwości kompilacji są określane w projektach tworzonych przez wersje visual C++ od 7.0 do 10.0. Jeśli przeprowadzisz migrację projektu utworzonego przez program Visual C++ 6.0, rozważ określenie wartości dla tych właściwości.

  • W programie Visual Studio 2010 runtimeLibrary = MultiThreaded (/MD) i DebugInformationFormat = ProgramDatabase (/Zi). W programie Visual C++ 9.0 runtimeLibrary = MultiThreaded (/MT) i DebugInformationFormat = Disabled.

CLR

  • Kompilatory języka Microsoft C# i Visual Basic mogą teraz utworzyć żaden podstawowy zestaw międzyoperacyjny (no-PIA). Zestaw no-PIA może używać typów COM bez wdrażania odpowiedniego podstawowego zestawu międzyoperaowego (PIA). W przypadku korzystania z zestawów bez pia utworzonych przez program Visual C# lub Visual Basic należy odwołać się do zestawu PIA w poleceniu kompilacji przed odwołaniem do dowolnego zestawu bez pia, który korzysta z biblioteki.

Projekty visual Studio C++ i program MSBuild

  • Projekty visual Studio C++ są teraz oparte na narzędziu MSBuild. W związku z tym pliki projektu używają nowego formatu pliku XML i sufiksu pliku .vcxproj. Program Visual Studio 2010 automatycznie konwertuje pliki projektu z wcześniejszych wersji programu Visual Studio na nowy format pliku. Problem dotyczy istniejącego projektu, jeśli zależy od poprzedniego narzędzia kompilacji, VCBUILD.exe lub sufiksu pliku projektu vcproj.

  • We wcześniejszych wersjach program Visual C++ obsługiwał późną ocenę arkuszy właściwości. Na przykład nadrzędny arkusz właściwości może zaimportować podrzędny arkusz właściwości, a obiekt nadrzędny może użyć zmiennej zdefiniowanej w elemecie podrzędnym w celu zdefiniowania innych zmiennych. Opóźniona ocena umożliwiła elementowi nadrzędnego używanie zmiennej podrzędnej jeszcze przed zaimportowanie podrzędnego arkusza właściwości. W programie Visual Studio 2010 nie można użyć zmiennej arkusza projektu przed jej zdefiniowaną, ponieważ program MSBuild obsługuje tylko wczesną ocenę.

IDE

  • Okno dialogowe kończenia działania aplikacji nie kończy już aplikacji. W poprzednich wersjach, gdy abort() funkcja or terminate() zamknęła kompilację detaliczną aplikacji, biblioteka czasu wykonywania języka C wyświetliła komunikat o zakończeniu działania aplikacji w oknie konsoli lub oknie dialogowym. Komunikat powiedział po części: "Ta aplikacja zażądała, aby środowisko uruchomieniowe zakończyło je w nietypowy sposób. Aby uzyskać więcej informacji, skontaktuj się z zespołem pomocy technicznej aplikacji. Komunikat o zakończeniu działania aplikacji był nadmiarowy, ponieważ system Windows wyświetlił bieżącą procedurę obsługi zakończenia, która była zwykle Raportowanie błędów systemu Windows (Dr. Watson) okno dialogowe lub debuger programu Visual Studio. Począwszy od programu Visual Studio 2010 biblioteka czasu wykonywania języka C nie wyświetla komunikatu. Ponadto środowisko uruchomieniowe uniemożliwia zakończenie aplikacji przed uruchomieniem debugera. Jest to zmiana powodująca niezgodność tylko wtedy, gdy zależysz od poprzedniego zachowania komunikatu o zakończeniu działania aplikacji.

  • W szczególności w przypadku programu Visual Studio 2010 funkcja IntelliSense nie działa w przypadku kodu lub atrybutów języka C++/interfejsu wiersza polecenia, funkcja Znajdź wszystkie odwołania nie działa w przypadku zmiennych lokalnych, a model kodu nie pobiera nazw typów z importowanych zestawów ani nie rozpoznaje typów do ich w pełni kwalifikowanych nazw.

Biblioteki

  • Klasa SafeInt jest uwzględniona w języku Visual C++ i nie jest już w osobnym pobieraniu. Jest to zmiana powodująca niezgodność tylko wtedy, gdy utworzono klasę o nazwie "SafeInt".

  • Model wdrażania bibliotek nie używa już manifestów do znalezienia konkretnej wersji biblioteki linków dynamicznych. Zamiast tego nazwa każdej biblioteki linków dynamicznych zawiera jego numer wersji i używasz tej nazwy do zlokalizowania biblioteki.

  • W poprzednich wersjach programu Visual Studio można ponownie skompilować biblioteki czasu wykonywania. Program Visual Studio 2010 nie obsługuje już tworzenia własnych kopii plików bibliotek czasu wykonywania języka C.

Standardowa biblioteka

  • Nagłówek <iterator> nie jest już automatycznie dołączany przez wiele innych plików nagłówków. Zamiast tego dołącz ten nagłówek jawnie, jeśli potrzebujesz obsługi autonomicznych iteratorów zdefiniowanych w nagłówku. Problem dotyczy istniejącego projektu, jeśli zależy od poprzedniego narzędzia kompilacji, VCBUILD.exe lub sufiksu pliku projektu vcproj.iterator.

  • W nagłówku <algorithm> checked_* funkcje i unchecked_* są usuwane. W nagłówku <iterator>> checked_iterator klasa zostanie usunięta, a unchecked_array_iterator klasa została dodana.

  • Konstruktor CComPtr::CComPtr(int) jest usuwany. Ten konstruktor zezwolił na CComPtr konstruowanie obiektu z makra NULL, ale był niepotrzebny i zezwalał na niesensowne konstrukcje z liczb całkowitych innych niż zero.

    Można CComPtr nadal utworzyć obiekt z wartości NULL, która jest zdefiniowana jako 0, ale zakończy się niepowodzeniem, jeśli zostanie skonstruowana z liczby całkowitej innej niż literał 0. Użycie w zamian parametru nullptr.

  • Usunięto następujące ctype funkcje składowe: ctype::_Do_narrow_s, , ctype::_narrow_sctype::_Do_widen_s, ctype::_widen_s. Jeśli aplikacja używa jednej z tych funkcji składowych, należy zastąpić ją odpowiednią wersją niezabezpieczoną: ctype::do_narrow, , ctype::narrowctype::do_widen, ctype::widen.

Biblioteki CRT, MFC i ATL

  • Obsługa została usunięta dla użytkowników w celu utworzenia bibliotek CRT, MFC i ATL. Na przykład nie podano odpowiedniego pliku NMAKE. Jednak użytkownicy nadal mają dostęp do kodu źródłowego dla tych bibliotek. Dokument opisujący opcje programu MSBuild używane przez firmę Microsoft do kompilowania tych bibliotek prawdopodobnie zostanie opublikowany w blogu zespołu visual C++.

  • Obsługa protokołu MFC dla IA64 została usunięta. Jednak wsparcie dla CRT i ATL w IA64 jest nadal zapewniane.

  • Reguły domyślne nie są już używane w plikach definicji modułu MFC (.def). Ta zmiana oznacza, że reguły nie będą się różnić między wersjami pomocniczymi, a zgodność binarna dodatków Service Pack i szybkie poprawki wydania inżynieryjne zostaną ulepszone.

  • Nowa funkcja wirtualna została dodana do CDocTemplate klasy. Ta nowa funkcja wirtualna to klasa CDocTemplate. Poprzednia wersja programu OpenDocumentFile miała dwa parametry. Nowa wersja ma trzy parametry. Aby obsługiwać menedżera ponownego uruchamiania, każda klasa pochodząca z CDocTemplate klasy musi zaimplementować wersję, która ma trzy parametry. Nowy parametr to bAddToMRU.

Makra i zmienne środowiskowe

  • Zmienna środowiskowa __MSVCRT_HEAP_SELECT nie jest już obsługiwana. Ta zmienna środowiskowa jest usuwana i nie ma zamiany.

Microsoft Macro Assembler — odwołanie

  • Kilka dyrektyw zostało usuniętych z kompilatora odwołań makr firmy Microsoft. Usunięte dyrektywy to .186, , .286, .286P.287, .8086, , .8087i .NO87.

Zmiany powodujące niezgodność programu Visual Studio 2008

Compiler

  • Platformy Windows 95, Windows 98, Windows ME i Windows NT nie są już obsługiwane. Te systemy operacyjne zostały usunięte z listy platform docelowych.

  • Kompilator nie obsługuje już wielu atrybutów, które zostały bezpośrednio skojarzone z serwerem ATL. Następujące atrybuty nie są już obsługiwane:

    • perf_counter

    • perf_object

    • perfmon

    • request_handler

    • soap_handler

    • soap_header

    • soap_method

    • tag_name

Projekty Visual Studio C++

  • Podczas uaktualniania projektów z poprzednich wersji programu Visual Studio może być konieczne zmodyfikowanie makr WINVER i _WIN32_WINNT tak, aby były większe lub równe 0x0500.

  • Począwszy od programu Visual Studio 2008, nowy kreator projektu nie ma możliwości utworzenia projektu C++ SQL Server. Projekty programu SQL Server utworzone przy użyciu starszej wersji programu Visual Studio będą nadal kompilować i działać poprawnie.

  • Plik nagłówka interfejsu API systemu Windows Winable.h został usunięty. Uwzględnij zamiast tego winuser.h.

  • Biblioteka interfejsu API systemu Windows Rpcndr.lib została usunięta. Zamiast tego połącz z rpcrt4.lib.

CRT

  • Usunięto obsługę systemów Windows 95, Windows 98, Windows Millennium Edition i Windows NT 4.0.

  • Usunięto następujące zmienne globalne:

    • _osplatform

    • _osver

    • _winmajor

    • _winminor

    • _winver

  • Następujące funkcje zostały usunięte. Użyj funkcji GetVersion interfejsu API systemu Windows lub GetVersionEx zamiast tego:

    • _get_osplatform

    • _get_osver

    • _get_winmajor

    • _get_winminor

    • _get_winver

  • Składnia adnotacji SAL została zmieniona. Aby uzyskać więcej informacji, zobacz Adnotacje SAL.

  • Filtr IEEE obsługuje teraz zestaw instrukcji SSE 4.1. Aby uzyskać więcej informacji, zobacz _fpieee_flt_fpieee_flt.

  • Biblioteki czasu wykonywania języka C dostarczane z programem Visual Studio nie są już zależne od systemowej biblioteki DLL msvcrt.dll.

Standardowa biblioteka

  • Usunięto obsługę systemów Windows 95, Windows 98, Windows Millennium Edition i Windows NT 4.0.

  • Podczas kompilowania w trybie debugowania przy użyciu _HAS_ITERATOR_DEBUGGING zdefiniowanych (zastąpionych przez _ITERATOR_DEBUG_LEVEL po programie Visual Studio 2010) aplikacja będzie teraz potwierdzać, gdy iterator próbuje zwiększać lub dekrementować granice bazowego kontenera.

  • Zmienna składowa c klasy stosu jest teraz zadeklarowana jako chroniona. Wcześniej ta zmienna składowa została zadeklarowana publicznie.

  • Zachowanie money_get::do_get metody uległo zmianie. Wcześniej podczas analizowania kwoty pieniężnej z większą liczbie cyfr ułamkowych niż są wywoływane przez frac_digitsprogram , do_get używane do ich użycia wszystkich. do_get Teraz zatrzymuje analizowanie po użyciu najwyżej frac_digits znaków.

ATL

  • Nie można skompilować atl bez zależności od CRT. We wcześniejszych wersjach programu Visual Studio można użyć #define ATL_MIN_CRT, aby projekt ATL był minimalnie zależny od CRT. W programie Visual Studio 2008 wszystkie projekty ATL są minimalnie zależne od CRT niezależnie od tego, czy ATL_MIN_CRT jest zdefiniowana.

  • Baza kodu serwera ATL została wydana jako udostępniony projekt źródłowy w pliku CodePlex i nie jest zainstalowana w ramach programu Visual Studio. Klasy kodowania i dekodowania danych z funkcji atlenc.h i narzędzi i klas z atlutil.h i atlpath.h zostały zachowane i są teraz częścią biblioteki ATL. Kilka plików skojarzonych z serwerem ATL nie jest już częścią programu Visual Studio.

  • Niektóre funkcje nie są już dołączone do biblioteki DLL. Nadal znajdują się one w bibliotece importu. Nie będzie to miało wpływu na kod, który statycznie używa funkcji. Będzie to miało wpływ tylko na kod, który dynamicznie używa tych funkcji.

  • Makra PROP_ENTRY i PROP_ENTRY_EX zostały wycofane i zastąpione makrami PROP_ENTRY_TYPE i PROP_ENTRY_TYPE_EX ze względów bezpieczeństwa.

Klasy współdzielone ATL/MFC

  • Nie można skompilować atl bez zależności od CRT. We wcześniejszych wersjach programu Visual Studio można użyć #define ATL_MIN_CRT polecenia , aby projekt ATL był minimalnie zależny od CRT. W programie Visual Studio 2008 wszystkie projekty ATL są minimalnie zależne od CRT niezależnie od tego, czy ATL_MIN_CRT jest zdefiniowana.

  • Baza kodu serwera ATL została wydana jako udostępniony projekt źródłowy w pliku CodePlex i nie jest zainstalowana w ramach programu Visual Studio. Klasy kodowania i dekodowania danych z funkcji atlenc.h i narzędzi i klas z atlutil.h i atlpath.h zostały zachowane i są teraz częścią biblioteki ATL. Kilka plików skojarzonych z serwerem ATL nie jest już częścią programu Visual Studio.

  • Niektóre funkcje nie są już dołączone do biblioteki DLL. Nadal znajdują się one w bibliotece importu. Nie będzie to miało wpływu na kod, który statycznie używa funkcji. Będzie to miało wpływ tylko na kod, który dynamicznie używa tych funkcji.

MFC

  • CTime Klasa: CTime Klasa akceptuje teraz daty od 1.1.1.1.1900 C.E. zamiast 1/1/1970 C.E.

  • Kolejność tabulatorów kontrolek w oknach dialogowych MFC: prawidłowa kolejność tabulacji wielu kontrolek w oknie dialogowym MFC jest zakłócona, jeśli kontrolka ActiveX MFC zostanie wstawiona w kolejności tabulacji. Ta zmiana naprawia ten problem.

    Na przykład utwórz aplikację dialogową MFC z kontrolką ActiveX i kilkoma kontrolkami edycji. Umieść kontrolkę ActiveX w środku kolejności tabulacji kontrolek edycji. Uruchom aplikację, kliknij kontrolkę edycji, której kolejność tabulacji znajduje się po kontrolce ActiveX, a następnie na karcie . Przed tą zmianą fokus przeszedł do kontrolki edycji po kontrolce ActiveX zamiast następnej kontrolki edycji w kolejności tabulacji.

  • CFileDialog Klasa: Szablony niestandardowe dla CFileDialog klasy nie mogą być automatycznie przenoszone do systemu Windows Vista. Są one nadal użyteczne, ale nie będą miały dodatkowej funkcjonalności ani okien dialogowych stylu systemu Windows Vista.

  • CWnd Klasa i CFrameWnd klasa: metoda została usunięta CWnd::GetMenuBarInfo .

    Metoda CFrameWnd::GetMenuBarInfo jest teraz metodą niewirtuacyjną. Aby uzyskać więcej informacji, zobacz GetMenuBarInfo Function in the Windows SDK (Funkcja GetMenuBarInfo w zestawie Windows SDK).

  • Obsługa interfejsu MFC ISAPI: MFC nie obsługuje już tworzenia aplikacji za pomocą internetowego interfejsu programowania aplikacji (ISAPI). Jeśli chcesz utworzyć aplikację ISAPI, wywołaj rozszerzenia ISAPI bezpośrednio.

  • Przestarzałe interfejsy API ANSI: wersje ANSI kilku metod MFC są przestarzałe. Użyj wersji Unicode tych metod w przyszłych aplikacjach. Aby uzyskać więcej informacji, zobacz Wymagania dotyczące kompilacji dla typowych kontrolek systemu Windows Vista.

Zmiany powodujące niezgodność programu Visual Studio 2005

CRT

  • Wiele funkcji zostało przestarzałych. Zobacz Przestarzałe funkcje CRT.

  • Wiele funkcji weryfikuje teraz parametry, zatrzymując wykonywanie, jeśli podano nieprawidłowe parametry. Ta walidacja może spowodować przerwanie kodu, który przekazuje nieprawidłowe parametry i opiera się na funkcji ignorując je lub po prostu zwracając kod błędu. Zobacz Walidacja parametrów.

  • Wartość deskryptora pliku -2 jest teraz używana do wskazania, że stdout dane wyjściowe i stderr nie są dostępne, na przykład w aplikacji systemu Windows, która nie ma okna konsoli. Użyta poprzednia wartość to -1. Aby uzyskać więcej informacji, zobacz _fileno.

  • Usunięto biblioteki CRT z jednym wątkiem (libc.lib i libcd.lib). Użyj wielowątowych bibliotek CRT. Flaga kompilatora /ML nie jest już obsługiwana. Nieblokujące wersje niektórych funkcji zostały dodane w przypadkach, gdy różnica wydajności między kodem wielowątkowym a kodem jednowątkowym jest potencjalnie znacząca.

  • Przeciążenie pow, double pow(int, int) zostało usunięte w celu lepszego zachowania zgodności ze standardem.

  • Specyfikator formatu %n nie jest już obsługiwany domyślnie w żadnej rodzinie funkcji printf, ponieważ jest z natury niezabezpieczony. W przypadku napotkania elementu %n domyślne zachowanie polega na wywołaniu nieprawidłowej procedury obsługi parametrów. Aby włączyć obsługę produktu %n, użyj polecenia _set_printf_count_output (zobacz _get_printf_count_outputrównież ).

  • sprintf teraz drukuje znak ujemny zeru ze znakiem.

  • swprintf została zmieniona tak, aby była zgodna ze standardem; teraz wymaga parametru rozmiaru. Postać bez parametru swprintf rozmiaru została przestarzała.

  • _set_security_error_handler został usunięty. Usuń wszystkie wywołania tej funkcji; domyślna procedura obsługi jest znacznie bezpieczniejszym sposobem radzenia sobie z błędami zabezpieczeń.

  • time_t jest teraz wartością 64-bitową (chyba że _USE_32BIT_TIME_T jest zdefiniowana).

  • _wspawn Funkcja _spawn, pozostawia errno teraz nietkniętą wartość powodzenia, jak określono w standardzie C.

  • Funkcja RTC domyślnie używa znaków szerokich.

  • Funkcje obsługi wyrazów sterowania zmiennoprzecinkowego zostały przestarzałe dla aplikacji skompilowanych za pomocą /CLR polecenia lub /CLR:PURE. Objęte funkcje to _clear87, , _clearfp, _control87, _controlfp_fpreset, , _status87, . _statusfp Możesz wyłączyć ostrzeżenie o wycofaniu, definiując _CRT_MANAGED_FP_NO_DEPRECATE, ale użycie tych funkcji w kodzie zarządzanym jest nieprzewidywalne i nieobsługiwane.

  • Niektóre funkcje zwracają teraz wskaźniki const. Stare, inne niż const zachowanie można przywrócić, definiując _CONST_RETURN. Funkcje, których dotyczy problem, są

    • memchr, wmemchr

    • strchr, wcschr, _mbschr, _mbschr_l

    • strpbrk, wcspbrk, _mbspbrk, _mbspbrk_l

    • strrchr, wcsrchr, _mbsrchr, _mbsrchr_l

    • strstr, wcsstr, _mbsstr, _mbsstr_l

  • Podczas łączenia z Setargv.obj lub Wsetargv.obj nie można już pominąć rozszerzania symbolu wieloznacznego w wierszu polecenia, umieszczając go w podwójnych cudzysłowach. Aby uzyskać więcej informacji, zobacz Rozwijanie argumentów wieloznacznych.

Standardowa biblioteka (2005)

  • Klasa wyjątku (znajdująca się w nagłówku <exception> ) została przeniesiona do std przestrzeni nazw. W poprzednich wersjach ta klasa znajdowała się w globalnej przestrzeni nazw. Aby usunąć wszelkie błędy wskazujące, że nie można odnaleźć klasy wyjątków, dodaj następującą instrukcję using do kodu: using namespace std;

  • Podczas wywoływania valarray::resize()metody zawartość valarray obiektu zostanie utracona i zostanie zamieniona na wartości domyślne. Metoda resize() ma na celu ponowne inicjowanie valarray zamiast dynamicznie rosnąć jak wektor.

  • Iteratory debugowania: aplikacje utworzone przy użyciu wersji debugowania biblioteki C-Runtime i używające iteratorów niepoprawnie mogą zaczynać widzieć aseracje w czasie wykonywania. Aby wyłączyć te potwierdzenia, należy zdefiniować _HAS_ITERATOR_DEBUGGING (zastąpione przez _ITERATOR_DEBUG_LEVEL program Visual Studio 2010) do 0. Aby uzyskać więcej informacji, zobacz Debugowanie obsługi iteratora

Zmiany powodujące niezgodność w programie Visual C++ .NET 2003

Compiler

  • Nawiasy zamykające są teraz wymagane dla zdefiniowanej dyrektywy preprocesora (C2004).

  • Jawne specjalizacje nie znajdują już parametrów szablonu z szablonu podstawowego (błąd kompilatora C2146).

  • Dostęp do chronionego elementu członkowskiego (n) można uzyskać tylko za pośrednictwem funkcji składowej klasy (B), która dziedziczy z klasy (A), której elementem członkowskim (n) jest składowa (błąd kompilatora C2247).

  • Ulepszone kontrole ułatwień dostępu w kompilatorze wykrywają teraz niedostępne klasy bazowe (błąd kompilatora C2248).

  • Nie można złapać wyjątku, jeśli destruktor i/lub konstruktor kopiowania jest niedostępny (C2316).

  • Domyślne argumenty wskaźników do funkcji nie są już dozwolone (błąd kompilatora C2383).

  • Nie można zainicjować statycznej składowej danych za pośrednictwem klasy pochodnej (błąd kompilatora C2477).

  • Inicjowanie elementu typedef nie jest dozwolone przez standard, a teraz generuje błąd kompilatora (błąd kompilatora C2513).

  • bool jest teraz odpowiednim typem (błąd kompilatora C2632).

  • Funkcja UDC może teraz tworzyć niejednoznaczność z przeciążonymi operatorami (C2666).

  • Więcej wyrażeń jest teraz uważanych za prawidłowe stałe wskaźnika null (błąd kompilatora C2668).

  • Szablon<> jest teraz wymagany w miejscach, w których kompilator wcześniej go sugerował (błąd kompilatora C2768).

  • Jawna specjalizacja funkcji składowej poza klasą jest nieprawidłowa, jeśli funkcja została już jawnie wyspecjalizowana za pomocą specjalizacji klasy szablonu (błąd kompilatora C2910).

  • Parametry szablonu innego niż typ zmiennoprzecinkowy nie są już dozwolone (błąd kompilatora C2993).

  • Szablony klas nie są dozwolone jako argumenty typu szablonu (C3206).

  • Nazwy funkcji znajomych nie są już wprowadzane do zawierającej przestrzeń nazw (błąd kompilatora C3767).

  • Kompilator nie będzie już akceptować dodatkowych przecinków w makrze (C4002).

  • Obiekt typu POD skonstruowany z inicjatorem formularza () zostanie zainicjowany domyślnie (C4345).

  • nazwa_typu jest teraz wymagana, jeśli nazwa zależna ma być traktowana jako typ (ostrzeżenie kompilatora (poziom 1) C4346).

  • Funkcje, które zostały nieprawidłowo uznane za specjalizacje szablonów, nie są już brane pod uwagę (C4347).

  • Statyczne składowe danych nie mogą być inicjowane za pośrednictwem klasy pochodnej (C4356).

  • Specjalizacja szablonu klasy musi być zdefiniowana, zanim będzie używana w typie zwracanym (ostrzeżenie kompilatora (poziom 3) C4686).

  • Kompilator zgłasza teraz niemożliwy do osiągnięcia kod (C4702).

Zobacz też

Co nowego w programie Visual C++ w programie Visual Studio