Riwayat perubahan Microsoft C/C++ 2003 - 2015

Artikel ini menjelaskan semua perubahan yang melanggar dari Visual Studio 2015 kembali ke Visual Studio 2003, dan dalam artikel ini istilah "perilaku baru" atau "sekarang" merujuk ke Visual Studio 2015 dan yang lebih baru. Istilah "perilaku lama" dan "sebelum" mengacu pada Visual Studio 2013 dan rilis sebelumnya.

Untuk informasi tentang versi terbaru Visual Studio, lihat Apa yang baru untuk C++ di Visual Studio dan peningkatan kesuaian C++ di Visual Studio.

Catatan

Tidak ada perubahan pemecahan biner antara Visual Studio 2015 dan Visual Studio 2017.

Saat meningkatkan ke versi baru Visual Studio, Anda mungkin mengalami kesalahan kompilasi dan/atau runtime dalam kode yang sebelumnya dikompilasi dan dijalankan dengan benar. Perubahan dalam versi baru yang menyebabkan masalah tersebut dikenal sebagai perubahan yang melanggar, dan biasanya diperlukan oleh modifikasi dalam standar bahasa C++, tanda tangan fungsi, atau tata letak objek dalam memori.

Untuk menghindari kesalahan run-time yang sulit dideteksi dan didiagnosis, kami sarankan Anda tidak pernah menautkan secara statis ke biner yang dikompilasi dengan menggunakan versi pengompilasi yang berbeda. Selain itu, saat Anda meningkatkan proyek EXE atau DLL, pastikan untuk meningkatkan pustaka yang ditautkannya. Jangan meneruskan jenis CRT (C Runtime) atau C++ Standard Library (C++ Standard Library) antar biner, termasuk DLL, yang dikompilasi dengan menggunakan versi kompiler yang berbeda. Untuk informasi selengkapnya, lihat Potensi Kesalahan Melewati Objek CRT Di Seluruh Batas DLL.

Anda tidak boleh menulis kode yang bergantung pada tata letak tertentu untuk objek yang bukan antarmuka COM atau objek POD. Jika Anda menulis kode tersebut, maka Anda harus memastikan bahwa kode tersebut berfungsi setelah Anda meningkatkan. Untuk informasi selengkapnya, lihat Portabilitas Di Batas ABI.

Selain itu, peningkatan berkelanjutan pada kesuaian kompilator terkadang dapat mengubah bagaimana pengkompilasi memahami kode sumber Anda yang ada. Misalnya, Anda mungkin menemukan kesalahan baru atau berbeda selama build Anda, atau bahkan perbedaan perilaku dalam kode yang sebelumnya dibangun dan tampaknya berjalan dengan benar. Meskipun peningkatan ini tidak melanggar perubahan seperti yang dibahas dalam dokumen ini, Anda mungkin perlu membuat perubahan pada kode sumber Anda untuk mengatasi masalah ini:

Perubahan Kesuaian Visual Studio 2015

Pustaka Runtime C (CRT)

Perubahan Umum

  • Biner yang direfaktor

    Pustaka CRT telah direfaktor menjadi dua biner berbeda: Universal CRT (ucrtbase), yang berisi sebagian besar fungsionalitas standar, dan Pustaka Runtime VC (vcruntime). Pustaka vcruntime berisi fungsionalitas terkait kompilator seperti penanganan pengecualian, dan intrinsik. Jika Anda menggunakan pengaturan proyek default, perubahan ini tidak memengaruhi Anda karena linker menggunakan pustaka default baru secara otomatis. Jika Anda telah mengatur properti Linker proyek Abaikan Semua Pustaka Default ke Ya atau Anda menggunakan /NODEFAULTLIB opsi linker pada baris perintah, maka Anda harus memperbarui daftar pustaka Anda (di properti Dependensi Tambahan) untuk menyertakan pustaka baru yang direfaktor. Ganti pustaka CRT lama (libcmt.lib, , libcmtd.libmsvcrt.lib, msvcrtd.lib) dengan pustaka yang direfaktor yang setara. Untuk masing-masing dari dua pustaka yang direfaktor, ada versi statis (.lib) dan dinamis (.dll), dan rilis (tanpa akhiran) dan versi debug (dengan akhiran "d"). Versi dinamis memiliki pustaka impor yang Anda tautkan. Dua pustaka yang direfaktor adalah Universal CRT, khususnya ucrtbase.dll atau ucrtbase.lib, ucrtbased.dll atau ucrtbased.lib, dan pustaka runtime VC, libvcruntime.lib, vcruntimeversion.dll, libvcruntimed.lib, dan vcruntimedversion.dll. Versi di Visual Studio 2015 dan Visual Studio 2017 adalah 140. Lihat Fitur Pustaka CRT.

<locale.h>

  • localeconv

    Fungsi localeconv yang dideklarasikan dalam locale.h sekarang berfungsi dengan benar ketika lokal per utas diaktifkan. Di versi pustaka sebelumnya, fungsi ini akan mengembalikan lconv data untuk lokal global, bukan lokal utas.

    Jika Anda menggunakan lokal per utas, Anda harus memeriksa penggunaan Anda .localeconv Jika kode Anda mengasumsikan bahwa data yang lconv dikembalikan adalah untuk lokal global, Anda harus memperbaikinya.

<math.h>

  • Kelebihan beban C++ fungsi pustaka matematika

    Dalam versi sebelumnya, <math.h> didefinisikan beberapa, tetapi tidak semua, dari C++ kelebihan beban untuk fungsi pustaka matematika. Sisa kelebihan beban berada di <cmath> header. Kode yang hanya disertakan <math.h> dapat memiliki masalah dengan resolusi kelebihan beban fungsi. Sekarang kelebihan beban C++ telah dihapus dari <math.h> dan hanya ditemukan di <cmath>.

    Untuk mengatasi kesalahan, sertakan <cmath> untuk mendapatkan deklarasi fungsi yang dihapus dari <math.h>. Fungsi-fungsi ini dipindahkan:

    • double abs(double) dan 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)
    • floatdan long double versi fungsi acostitik mengambang , , , acosh, llroundatanhatan2cbrtceilcopysignatancoshcoserferfcexpexp2expm1asinhfdimfabsfloorfmafmaxfminlog10loglog1pllrintlgammaldexplog2ilogbhypotfrexplrintasinscalblnroundfmodnextafternexttowardnearbyintremaindermodfremquosinhscalbnrintlroundsqrttansin, tanh, , dan tgammatrunc

    Jika Anda memiliki kode yang menggunakan abs dengan jenis titik mengambang yang hanya menyertakan <math.h> header, versi titik mengambang tidak akan tersedia lagi. Panggilan sekarang diselesaikan ke abs(int), bahkan dengan argumen floating point, yang menghasilkan kesalahan:

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

    Perbaikan untuk peringatan ini adalah mengganti panggilan ke abs dengan versi titik mengambang dari abs, seperti fabs untuk argumen ganda atau fabsf untuk argumen float, atau menyertakan <cmath> header dan terus menggunakan abs.

  • Kesuaian titik mengambang

    Banyak perubahan pada pustaka matematika telah dilakukan untuk meningkatkan kesamaan dengan spesifikasi IEEE-754 dan C11 Annex F sehubungan dengan input kasus khusus seperti NaN dan tak terbatas. Misalnya, input NaN yang tenang, yang sering diperlakukan sebagai kesalahan dalam versi pustaka sebelumnya, tidak lagi diperlakukan sebagai kesalahan. Lihat IEEE 754 Standard dan Annex F dari C11 Standard.

    Perubahan ini tidak akan menyebabkan kesalahan waktu kompilasi, tetapi dapat menyebabkan program berulah secara berbeda dan lebih benar sesuai dengan standar.

  • FLT_ROUNDS

    Di Visual Studio 2013, makro FLT_ROUNDS diperluas ke ekspresi konstanta, yang salah karena mode pembulatan dapat dikonfigurasi saat runtime, misalnya, dengan memanggil fesetround. Makro FLT_ROUNDS sekarang dinamis dan mencerminkan mode pembulatan saat ini dengan benar.

<new> dan <new.h>

  • new dan delete

    Dalam versi pustaka sebelumnya, fungsi baru dan penghapusan operator yang ditentukan implementasi diekspor dari DLL pustaka runtime (misalnya, msvcr120.dll). Fungsi operator ini sekarang selalu ditautkan secara statis ke biner Anda, bahkan saat menggunakan DLL pustaka runtime.

    Ini bukan perubahan yang melanggar untuk kode asli atau campuran (/clr), namun untuk kode yang dikompilasi sebagai /clr:pure, perubahan ini dapat menyebabkan kode Anda gagal dikompilasi. Jika Anda mengkompilasi kode sebagai /clr:pure, Anda mungkin perlu menambahkan #include <new> atau #include <new.h> untuk mengatasi kesalahan build karena perubahan ini. Opsi/clr:pure tidak digunakan lagi di Visual Studio 2015 dan tidak didukung di Visual Studio 2017. Kode yang perlu "murni" harus di-port ke C#.

<process.h>

  • _beginthread dan _beginthreadex

    Fungsi _beginthread dan _beginthreadex sekarang menyimpan referensi ke modul tempat prosedur utas didefinisikan selama durasi utas. Ini membantu memastikan bahwa modul tidak dibongkar hingga utas berjalan hingga selesai.

<stdarg.h>

  • va_start dan jenis referensi

    Saat mengkompilasi kode C++, va_start sekarang memvalidasi pada waktu kompilasi bahwa argumen yang diteruskan ke itu bukan jenis referensi. Argumen jenis referensi dilarang oleh Standar C++.

<stdio.h> dan <conio.h>

  • Keluarga fungsi cetak dan pemindaian sekarang didefinisikan sebaris.

    Definisi semua printf fungsi dan scanf telah dipindahkan sebaris ke , <stdio.h><conio.h>, dan header CRT lainnya. Perubahan yang melanggar ini menyebabkan kesalahan linker (LNK2019, simbol eksternal yang tidak terselesaikan) untuk program apa pun yang mendeklarasikan fungsi ini secara lokal tanpa menyertakan header CRT yang sesuai. Jika memungkinkan, Anda harus memperbarui kode untuk menyertakan header CRT (yaitu, tambahkan #include <stdio.h>) dan fungsi sebaris, tetapi jika Anda tidak ingin mengubah kode Anda untuk menyertakan file header ini, solusi alternatifnya adalah menambahkan legacy_stdio_definitions.lib ke input linker Anda.

    Untuk menambahkan pustaka ini ke input linker Anda di IDE, buka menu konteks untuk simpul proyek, pilih Properti, lalu di kotak dialog Properti Proyek, pilih Linker, dan edit Input Linker untuk ditambahkan legacy_stdio_definitions.lib ke daftar yang dipisahkan titik koma.

    Jika proyek Anda ditautkan dengan pustaka statis yang dikompilasi dengan rilis Visual Studio lebih awal dari 2015, linker mungkin melaporkan simbol eksternal yang belum terselesaikan. Kesalahan ini mungkin mereferensikan definisi internal untuk _iob, , _iob_funcatau impor terkait untuk fungsi tertentu <stdio.h> dalam bentuk imp*. Microsoft menyarankan agar Anda mengkompilasi ulang semua pustaka statis dengan versi terbaru pengkompilasi dan pustaka C++ saat Anda meningkatkan proyek. Jika pustaka adalah pustaka pihak ketiga yang sumbernya tidak tersedia, Anda harus meminta biner yang diperbarui dari pihak ketiga atau merangkum penggunaan pustaka tersebut ke dll terpisah yang Anda kompilasi dengan versi kompilator dan pustaka yang lebih lama.

    Peringatan

    Jika Anda menautkan dengan Windows SDK 8.1 atau yang lebih lama, Anda mungkin mengalami kesalahan simbol eksternal yang belum terselesaikan ini. Dalam hal ini, Anda harus mengatasi kesalahan dengan menambahkan legacy_stdio_definitions.lib ke input linker seperti yang dijelaskan sebelumnya.

    Untuk memecahkan masalah kesalahan simbol yang belum terselesaikan, Anda dapat mencoba menggunakan dumpbin.exe untuk memeriksa simbol yang ditentukan dalam biner. Coba baris perintah berikut untuk melihat simbol yang ditentukan dalam pustaka.

    dumpbin.exe /LINKERMEMBER somelibrary.lib
    
  • mendapatkan dan _getws

    Fungsi gets dan _getws telah dihapus. Fungsi gets dihapus dari Pustaka Standar C di C11 karena tidak dapat digunakan dengan aman. Fungsi _getws adalah ekstensi Microsoft yang setara dengan mendapatkan tetapi untuk string lebar. Sebagai alternatif untuk fungsi-fungsi ini, pertimbangkan penggunaan fget, fgetw, gets_s, dan _getws_s.

  • _cgets dan _cgetws

    Fungsi _cgets dan _cgetws telah dihapus. Sebagai alternatif untuk fungsi-fungsi ini, pertimbangkan penggunaan _cgets_s dan _cgetws_s.

  • Pemformatan Infinity dan NaN

    Dalam versi sebelumnya, infinities dan NaN akan diformat menggunakan sekumpulan string sentinel khusus MSVC.

    • Tak terbatas: 1.#INF

    • NaN Tenang: 1.#QNAN

    • NaN Sinyal: 1.#SNAN

    • NaN tak terbatas: 1.#IND

    Salah satu format ini mungkin telah diawali oleh tanda dan mungkin telah diformat sedikit berbeda tergantung pada lebar bidang dan presisi (kadang-kadang dengan efek yang tidak biasa, misalnya printf("%.2f\n", INFINITY) akan mencetak 1,#J karena #INF akan "dibulatkan" ke presisi 2 digit). C99 memperkenalkan persyaratan baru tentang bagaimana infinities dan NaN akan diformat. Implementasi MSVC sekarang sesuai dengan persyaratan ini. String baru adalah sebagai berikut:

    • Tak terbatas: inf

    • NaN tenang: nan

    • NaN Sinyal: nan(snan)

    • NaN Tak Terbatas: nan(ind)

    Salah satu dari ini dapat diawali dengan tanda. Jika penentu format kapital digunakan (%F alih-alih %f), maka string dicetak dalam huruf kapital (INF bukan inf), seperti yang diperlukan.

    Fungsi pemindaian telah dimodifikasi untuk mengurai string baru ini, sehingga string ini sekarang melakukan printf perjalanan pulang pergi dan scanf.

  • Pemformatan dan penguraian titik mengambang

    Pemformatan titik mengambang baru dan algoritma penguraian telah diperkenalkan untuk meningkatkan kebenaran. Perubahan ini memengaruhi keluarga fungsi cetak dan pemindaian , dan fungsi seperti strtod.

    Algoritma pemformatan lama hanya akan menghasilkan sejumlah digit terbatas, kemudian akan mengisi tempat desimal yang tersisa dengan nol. Mereka biasanya dapat menghasilkan string yang akan pulang-pergi kembali ke nilai titik mengambang asli, tetapi tidak bagus jika Anda menginginkan nilai yang tepat (atau representasi desimal terdekat darinya). Algoritma pemformatan baru menghasilkan digit sebanyak yang diperlukan untuk mewakili nilai (atau untuk mengisi presisi yang ditentukan). Sebagai contoh peningkatan; pertimbangkan hasilnya saat mencetak kekuatan besar dua:

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

    Output lama:

    1208925819614629200000000
    

    Output baru:

    1208925819614629174706176
    

    Algoritma penguraian lama hanya akan mempertimbangkan hingga 17 digit signifikan dari string input dan akan membuang digit lainnya. Pendekatan ini cukup untuk menghasilkan perkiraan dekat dari nilai yang diwakili oleh string, dan hasilnya biasanya sangat dekat dengan hasil yang dibulatkan dengan benar. Implementasi baru mempertimbangkan semua digit yang ada dan menghasilkan hasil yang dibulatkan dengan benar untuk semua input (panjangnya hingga 768 digit). Selain itu, fungsi-fungsi ini sekarang menghormati mode pembulatan (dapat dikontrol melalui fesetround). Ini berpotensi menjadi perubahan perilaku yang melanggar karena fungsi-fungsi ini mungkin menghasilkan hasil yang berbeda. Hasil baru selalu lebih benar daripada hasil lama.

  • Penguraian titik float heksadesimal dan tak terbatas/NaN

    Algoritma penguraian titik mengambang sekarang akan mengurai string titik mengambang heksadesimal (seperti yang dihasilkan oleh penentu format cetak %a dan %A) dan semua string tak terbatas dan NaN yang dihasilkan oleh printf fungsi, seperti yang dijelaskan di atas.

  • %A dan %a zero padding

    Penentu format %a dan %A memformat angka titik mengambang sebagai mantissa heksadesimal dan eksponen biner. Dalam versi sebelumnya, printf fungsi akan salah untai (karakter) zero-pad. Misalnya, printf("%07.0a\n", 1.0) akan mencetak 00x1p+0, di mana harus mencetak 0x01p+0. Kelemahan ini telah diperbaiki.

  • %A dan %a presisi

    Presisi default dari %A dan %a penentu format adalah 6 di versi pustaka sebelumnya. Presisi default sekarang adalah 13 untuk kesamaan dengan Standar C.

    Ini adalah perubahan perilaku runtime dalam output fungsi apa pun yang menggunakan string format dengan %A atau %a. Dalam perilaku lama, output yang menggunakan penentu %A mungkin adalah "1.1A2B3Cp+111". Sekarang output untuk nilai yang sama adalah "1.1A2B3C4D5E6F7p+111". Untuk mendapatkan perilaku lama, Anda dapat menentukan presisi, misalnya, %.6A. Lihat Spesifikasi Presisi.

  • %F penentu

    Penentu %F format/konversi sekarang didukung. Ini secara fungsional setara dengan penentu format %f, kecuali bahwa infinities dan NaN diformat menggunakan huruf kapital.

    Pada versi sebelumnya, implementasi yang digunakan untuk mengurai F dan N sebagai pengubah panjang. Perilaku ini bertanggal kembali ke usia ruang alamat tersegmentasi: pengubah panjang ini digunakan untuk menunjukkan penunjuk yang jauh dan dekat, masing-masing, seperti dalam %Fp atau %Ns. Perilaku ini telah dihapus. Jika %F ditemukan, sekarang diperlakukan sebagai penentu format %F; jika %N ditemui, sekarang diperlakukan sebagai parameter yang tidak valid.

  • Pemformatan eksponen

    Penentu format %e dan %E memformat angka titik mengambang sebagai mantissa desimal dan eksponen. Penentu format %g dan %G juga memformat angka dalam formulir ini dalam beberapa kasus. Di versi sebelumnya, CRT akan selalu menghasilkan string dengan eksponen tiga digit. Misalnya, printf("%e\n", 1.0) akan mencetak 1.000000e+000, yang salah. C mengharuskan jika eksponen dapat diwakili hanya menggunakan satu atau dua digit, maka hanya dua digit yang akan dicetak.

    Di Visual Studio 2005, sakelar kesuaian global ditambahkan: _set_output_format. Program dapat memanggil fungsi ini dengan argumen _TWO_DIGIT_EXPONENT, untuk mengaktifkan pencetakan eksponen yang sesuai. Perilaku default telah diubah ke mode pencetakan eksponen yang sesuai standar.

  • Validasi string format

    Dalam versi sebelumnya, printf fungsi dan scanf akan secara diam-diam menerima banyak string format yang tidak valid, kadang-kadang dengan efek yang tidak biasa. Misalnya, %hlhlhld akan diperlakukan sebagai %d. Semua string format yang tidak valid sekarang diperlakukan sebagai parameter yang tidak valid.

  • validasi string mode fopen

    Dalam versi sebelumnya, fopen keluarga fungsi secara diam-diam menerima beberapa string mode yang tidak valid, seperti r+b+. String mode tidak valid sekarang terdeteksi dan diperlakukan sebagai parameter yang tidak valid.

  • mode _O_U8TEXT

    Fungsi _setmode sekarang melaporkan mode untuk streaming yang dibuka dengan benar in_O_U8TEXT mode. Di versi pustaka sebelumnya, pustaka akan melaporkan aliran seperti yang dibuka di _O_WTEXT.

    Ini adalah perubahan yang melanggar jika kode Anda menginterpretasikan mode _O_WTEXT untuk streaming di mana pengodean adalah UTF-8. Jika aplikasi Anda tidak mendukung UTF_8, pertimbangkan untuk menambahkan dukungan untuk pengodean yang semakin umum ini.

  • snprintf dan vsnprintf

    Fungsi snprintf dan vsnprintf sekarang diimplementasikan. Kode lama sering memberikan definisi versi makro dari fungsi-fungsi ini karena tidak diimplementasikan oleh pustaka CRT, tetapi tidak lagi diperlukan dalam versi yang lebih baru. Jika snprintf atau vsnprintf didefinisikan sebagai makro sebelum menyertakan <stdio.h>, kompilasi sekarang gagal dengan kesalahan yang menunjukkan di mana makro ditentukan.

    Biasanya, perbaikan untuk masalah ini adalah menghapus deklarasi snprintf atau vsnprintf dalam kode pengguna.

  • tmpnam Menghasilkan Nama File yang Dapat Digunakan

    Dalam versi sebelumnya, tmpnam fungsi dan tmpnam_s menghasilkan nama file di akar drive (seperti \sd3c.). Fungsi-fungsi ini sekarang menghasilkan jalur nama file yang dapat digunakan dalam direktori sementara.

  • Enkapsulasi FILE

    Dalam versi sebelumnya, jenis FILE lengkap didefinisikan secara publik di <stdio.h>, sehingga dimungkinkan bagi kode pengguna untuk menjangkau file dan memodifikasi internalnya. Pustaka telah diubah untuk menyembunyikan detail implementasi. Sebagai bagian dari perubahan ini, FILE seperti yang didefinisikan sekarang <stdio.h> adalah jenis buram dan anggotanya tidak dapat diakses dari luar CRT itu sendiri.

  • _outp dan _inp

    Fungsi _outp, _outpw, _outpd, _inp, _inpw, dan _inpd telah dihapus.

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

  • strtof dan wcstof

    Fungsi strtof dan wcstof gagal diatur errno ke ERANGE ketika nilai tidak dapat diwakili sebagai float. Kesalahan ini khusus untuk kedua fungsi ini; strtodfungsi , wcstod, strtold, dan wcstold tidak terpengaruh. Masalah ini telah diperbaiki, dan merupakan perubahan yang melanggar runtime.

  • Fungsi alokasi yang diratakan

    Dalam versi sebelumnya, fungsi alokasi yang selaras (_aligned_malloc, , _aligned_offset_mallocdll.) akan secara diam-diam menerima permintaan untuk blok dengan penyelarasan 0. Perataan yang diminta harus berupa kekuatan dua, yang tidak benar dari nol. Penyelarasan 0 yang diminta sekarang diperlakukan sebagai parameter yang tidak valid. Masalah ini telah diperbaiki, dan merupakan perubahan yang melanggar runtime.

  • Fungsi timbunan

    Fungsi _heapadd, _heapset, dan _heapused telah dihapus. Fungsi-fungsi ini tidak berfungsi sejak CRT diperbarui untuk menggunakan tumpukan Windows.

  • smallheap

    Opsi smallheap tautan telah dihapus. Lihat Opsi Tautan.

  • _Stat

    Keluarga _stat fungsi digunakan CreateFile di Visual Studio 2015, alih-alih FindFirstFile seperti di Visual Studio 2013 dan yang lebih lama. Ini berarti bahwa pada jalur yang _stat diakhir dengan garis miring berhasil jika jalur mengacu pada direktori, dibandingkan dengan sebelumnya ketika fungsi akan kesalahan dengan errno diatur ke ENOENT.

<string.h>

  • wcstok

    Tanda tangan wcstok fungsi telah diubah agar sesuai dengan apa yang diperlukan oleh Standar C. Di versi pustaka sebelumnya, tanda tangan fungsi ini adalah:

    wchar_t* wcstok(wchar_t*, wchar_t const*)
    

    Ini menggunakan konteks internal per utas untuk melacak status di seluruh panggilan, seperti yang dilakukan untuk strtok. Fungsi sekarang memiliki tanda tangan wchar_t* wcstok(wchar_t*, wchar_t const*, wchar_t**), dan mengharuskan pemanggil untuk meneruskan konteks sebagai argumen ketiga ke fungsi.

    Fungsi baru _wcstok telah ditambahkan dengan tanda tangan lama untuk memudahkan porting. Saat mengkompilasi kode C++, ada juga kelebihan wcstok sebaris yang memiliki tanda tangan lama. Kelebihan beban ini dinyatakan tidak digunakan lagi. Dalam kode C, Anda dapat define_CRT_NON_CONFORMING_WCSTOK menyebabkan _wcstok digunakan sebagai pengganti wcstok.

<time.h>

  • Jam

    Di versi sebelumnya, clock fungsi diimplementasikan menggunakan Windows API GetSystemTimeAsFileTime. Dengan implementasi ini, fungsi jam sensitif terhadap waktu sistem, dan dengan demikian tidak selalu monoton. Fungsi jam telah diisi ulang dalam hal QueryPerformanceCounter dan sekarang monoton.

  • fstat dan _utime

    Dalam versi sebelumnya, _statfungsi , , fstatdan _utime salah menangani waktu penghematan siang hari. Sebelum Visual Studio 2013, semua fungsi ini salah menyesuaikan waktu standar seolah-olah mereka berada di siang hari.

    Di Visual Studio 2013, masalah diperbaiki dalam _stat keluarga fungsi, tetapi masalah serupa dalam fstat keluarga fungsi dan _utime tidak diperbaiki. Perbaikan parsial ini menyebabkan masalah karena ketidakkonsistensian antara fungsi. Keluarga fstat fungsi dan _utime sekarang telah diperbaiki, sehingga semua fungsi ini sekarang menangani waktu penghematan siang hari dengan benar dan konsisten.

  • asktime

    Dalam versi sebelumnya, fungsi akan mengalihkan asctime satu digit hari dengan nol di depannya, misalnya: Fri Jun 06 08:00:00 2014. Spesifikasi mengharuskan hari-hari seperti itu di-padding dengan ruang depan, seperti dalam Fri Jun 6 08:00:00 2014. Masalah ini telah diperbaiki.

  • strftime dan wcsftime

    Fungsi strftime dan wcsftime sekarang mendukung penentu format %C, %D, %e, %F, %g, %G, %h, %n, %r, %R, %t, %T, %u, dan %V. Selain itu, pengubah E dan O diurai tetapi diabaikan.

    Penentu format %c ditentukan sebagai menghasilkan "representasi tanggal dan waktu yang sesuai" untuk lokal saat ini. Dalam lokal C, representasi ini harus sama dengan %a %b %e %T %Y, bentuk yang sama seperti yang diproduksi oleh asctime. Dalam versi sebelumnya, penentu format %c waktu yang salah diformat menggunakan MM/DD/YY HH:MM:SS representasi. Masalah ini telah diperbaiki.

  • timespec dan TIME_UTC

    Header <time.h> sekarang menentukan timespec jenis dan timespec_get fungsi dari Standar C11. Selain itu, makro TIME_UTC, untuk digunakan dengan timespec_get fungsi, sekarang ditentukan. Pembaruan ini adalah perubahan yang melanggar untuk kode yang memiliki definisi yang bertentangan untuk salah satu pengidentifikasi ini.

  • CLOCKS_PER_SEC

    Makro CLOCKS_PER_SEC sekarang meluas ke bilangan bulat jenis clock_t, seperti yang diperlukan oleh bahasa C.

Pustaka Standar C++

Untuk mengaktifkan pengoptimalan baru dan pemeriksaan penelusuran kesalahan, implementasi Visual Studio dari Pustaka Standar C++ sengaja memutuskan kompatibilitas biner dari satu versi ke versi berikutnya. Oleh karena itu, ketika Pustaka Standar C++ digunakan, file objek dan pustaka statis yang dikompilasi dengan menggunakan versi yang berbeda tidak dapat dicampur dalam satu biner (EXE atau DLL), dan objek Pustaka Standar C++ tidak dapat diteruskan di antara biner yang dikompilasi dengan menggunakan versi yang berbeda. Pencampuran tersebut memancarkan kesalahan linker tentang ketidakcocokan _MSC_VER. (_MSC_VER adalah makro yang berisi versi utama pengkompilasi—misalnya, 1800 untuk Visual Studio 2013.) Pemeriksaan ini tidak dapat mendeteksi pencampuran DLL, dan tidak dapat mendeteksi pencampuran yang melibatkan Visual Studio 2008 atau yang lebih lama.

  • Pustaka Standar C++ menyertakan file

    Beberapa perubahan telah dilakukan pada struktur include di header Pustaka Standar C++. Header Pustaka Standar C++ diizinkan untuk menyertakan satu sama lain dengan cara yang tidak ditentukan. Secara umum, Anda harus menulis kode Anda sehingga dengan hati-hati menyertakan semua header yang dibutuhkan sesuai dengan standar C++, dan tidak bergantung pada header Pustaka Standar C++ mana yang menyertakan header Pustaka Standar C++ lainnya. Ini membuat kode portabel di seluruh versi dan platform. Setidaknya dua perubahan header di Visual Studio 2015 memengaruhi kode pengguna. Pertama, <string> tidak lagi termasuk <iterator>. Kedua, <tuple> sekarang menyatakan std::array tanpa menyertakan semua <array>, yang dapat memecahkan kode melalui kombinasi konstruksi kode berikut: kode Anda memiliki variabel bernama "array", dan Anda memiliki direktif penggunaan "menggunakan namespace std;", dan Anda menyertakan header Pustaka Standar C++ (seperti <functional>) yang mencakup <tuple>, yang sekarang menyatakan std::array.

  • steady_clock

    Implementasi <chrono>steady_clock telah berubah untuk memenuhi persyaratan Standar C++ untuk ketepatan dan monotonisitas. steady_clock sekarang didasarkan pada QueryPerformanceCounter dan high_resolution_clock sekarang menjadi typedef untuk steady_clock. Akibatnya, di Visual Studio steady_clock::time_point sekarang menjadi typedef untuk chrono::time_point<steady_clock>; namun, ini belum tentu terjadi untuk implementasi lain.

  • alokator dan const

    Kami sekarang memerlukan perbandingan kesetaraan/ketidaksetaraan alokator untuk menerima argumen const di kedua sisi. Jika alokator Anda menentukan operator ini seperti ini,

    bool operator==(const MyAlloc& other)
    

    maka Anda harus memperbaruinya dan menyatakannya sebagai anggota const:

    bool operator==(const MyAlloc& other) const
    
  • elemen const

    Standar C++ selalu melarang kontainer elemen const (seperti vector<const T> atau set<const T>). Visual Studio 2013 dan sebelumnya menerima kontainer tersebut. Dalam versi saat ini, kontainer tersebut gagal dikompilasi.

  • std::allocator::d eallocate

    Di Visual Studio 2013 dan yang lebih lama, std::allocator::deallocate(p, n) abaikan argumen yang diteruskan untuk n. Standar C++ selalu mengharuskan n harus sama dengan nilai yang diteruskan sebagai argumen pertama untuk pemanggilan allocate, yang mengembalikan p. Namun, dalam versi saat ini, nilai n diperiksa. Kode yang meneruskan argumen untuk n yang berbeda dari apa yang diperlukan standar mungkin crash saat runtime.

  • hash_map dan hash_set

    File <hash_map> header non-standar dan <hash_set> tidak digunakan lagi di Visual Studio 2015 dan akan dihapus dalam rilis mendatang. Gunakan <unordered_map> dan <unordered_set> sebagai gantinya.

  • komparator dan operator()

    Kontainer asosiatif ( <map> keluarga) sekarang mengharuskan komparator mereka untuk memiliki operator panggilan fungsi yang dapat dipanggil secara const. Kode berikut dalam deklarasi kelas komparator sekarang gagal dikompilasi:

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

    Untuk mengatasi kesalahan ini, ubah deklarasi fungsi menjadi:

    bool operator()(const X& a, const X& b) const
    
  • jenis sifat

    Nama lama untuk sifat jenis dari versi standar draf C++ yang lebih lama telah dihapus. Ini diubah di C++11 dan telah diperbarui ke nilai C++11 di Visual Studio 2015. Tabel berikut ini memperlihatkan nama lama dan baru.

    Nama lama Nama baru
    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 dan launch::sync policies

    Kebijakan dan launch::sync nonstandard launch::any dihapus. Sebagai gantinya, untuk launch::any, gunakan launch:async | launch:deferred. Untuk launch::sync, gunakan launch::deferred. Lihat meluncurkan Enumerasi.

MFC dan ATL

  • Kelas Microsoft Foundation (MFC)

    tidak lagi disertakan dalam penginstalan Visual Studio "Khas" karena ukurannya yang besar. Untuk menginstal MFC, pilih opsi Penginstalan kustom di penyiapan Visual Studio 2015. Jika Anda sudah menginstal Visual Studio 2015, Anda dapat menginstal MFC dengan menjalankan penyiapan Visual Studio lagi. Pilih opsi Instal kustom, lalu pilih Kelas Microsoft Foundation. Anda dapat menjalankan penyiapan Visual Studio dari Panel Kontrol mengontrol Program dan Fitur, atau dari media penginstalan.

    Paket Visual C++ Redistributable masih menyertakan pustaka ini.

Runtime Konkurensi

  • Menghasilkan makro dari Windows.h yang bertentangan dengan konkurensi::Context::Yield

    Runtime Konkurensi yang sebelumnya digunakan #undef untuk tidak menentukan makro Hasil untuk menghindari konflik antara makro Yield yang ditentukan dalam Windows.h h dan concurrency::Context::Yield fungsi . Ini #undef telah dihapus dan konkurensi panggilan API setara yang tidak bertentangan baru::Context::YieldExecution telah ditambahkan. Untuk mengatasi konflik dengan Yield, Anda dapat memperbarui kode untuk memanggil YieldExecution fungsi sebagai gantinya, atau mengelilingi Yield nama fungsi dengan tanda kurung di situs panggilan, seperti dalam contoh berikut:

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

Peningkatan Kesuaian Kompilator di Visual Studio 2015

Saat meningkatkan kode dari versi sebelumnya, Anda mungkin juga mengalami kesalahan kompilator yang disebabkan oleh peningkatan kesuaian yang dilakukan di Visual Studio 2015. Peningkatan ini tidak merusak kompatibilitas biner dari versi Visual Studio sebelumnya, tetapi dapat menghasilkan kesalahan pengkompilasi di mana tidak ada yang dipancarkan sebelumnya. Untuk informasi selengkapnya, lihat Visual C++ Apa yang Baru 2003 hingga 2015.

Di Visual Studio 2015, peningkatan berkelanjutan pada kesuaian kompilator terkadang dapat mengubah cara pengkompilasi memahami kode sumber yang ada. Akibatnya, Anda mungkin mengalami kesalahan baru atau berbeda selama build Anda, atau bahkan perbedaan perilaku dalam kode yang sebelumnya dibangun dan tampaknya berjalan dengan benar.

Untungnya, perbedaan ini memiliki sedikit atau tidak berdampak pada sebagian besar kode sumber Anda. Ketika kode sumber atau perubahan lain diperlukan untuk mengatasi perbedaan ini, perbaikan cenderung kecil dan lurus ke depan. Kami telah menyertakan banyak contoh kode sumber yang dapat diterima sebelumnya yang mungkin perlu diubah (sebelumnya) dan perbaikan untuk memperbaikinya (setelah).

Meskipun perbedaan ini dapat memengaruhi kode sumber Anda atau artefak build lainnya, perbedaan tersebut tidak memengaruhi kompatibilitas biner antara pembaruan ke versi Visual Studio. Perubahan yang melanggar lebih parah, dan dapat memengaruhi kompatibilitas biner, tetapi jenis pemutusan kompatibilitas biner ini hanya terjadi antara versi utama Visual Studio, misalnya, antara Visual Studio 2013 dan Visual Studio 2015. Untuk informasi tentang perubahan mencolok yang terjadi antara Visual Studio 2013 dan Visual Studio 2015, lihat Perubahan Kesamaan Visual Studio 2015.

Peningkatan Kesuaian di Visual Studio 2015

  • Opsi /Zc:forScope-

    Opsi /Zc:forScope- kompilator tidak digunakan lagi dan akan dihapus dalam rilis mendatang.

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

    Biasanya, opsi ini digunakan untuk memungkinkan kode non-standar yang menggunakan variabel perulangan setelah titik di mana, sesuai dengan standar, mereka harus keluar dari cakupan. Itu hanya diperlukan ketika Anda mengkompilasi dengan /Za opsi, karena tanpa /Za, penggunaan variabel untuk perulangan setelah akhir perulangan selalu diizinkan. Jika Anda tidak peduli tentang kesuaian standar (misalnya, jika kode Anda tidak dimaksudkan untuk portabel ke pengkompilasi lain), Anda dapat menonaktifkan /Za opsi (atau mengatur properti Nonaktifkan Ekstensi Bahasa ke Tidak). Jika Anda peduli tentang menulis kode portabel dan sesuai standar, Anda harus menulis ulang kode Anda sehingga sesuai dengan standar dengan memindahkan deklarasi variabel tersebut ke titik di luar perulangan.

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

    Opsi /Zg pengkompilasi (Hasilkan Prototipe Fungsi) tidak lagi tersedia. Opsi kompilator ini sebelumnya tidak digunakan lagi.

  • Anda tidak dapat lagi menjalankan pengujian unit dengan C++/CLI dari baris perintah dengan mstest.exe. Sebagai gantinya, gunakan vstest.console.exe. Lihat opsi baris perintah VSTest.Console.exe.

  • kata kunci yang dapat diubah

    Penentu mutable kelas penyimpanan tidak lagi diizinkan di tempat-tempat di mana sebelumnya dikompilasi tanpa kesalahan. Sekarang, kompilator memberikan kesalahan C2071 (kelas penyimpanan ilegal). Menurut standar, penentu mutable hanya dapat diterapkan ke nama anggota data kelas, dan tidak dapat diterapkan ke nama yang dinyatakan const atau statis, dan tidak dapat diterapkan ke anggota referensi.

    Sebagai contoh, perhatikan kode berikut:

    struct S
    {
        mutable int &r;
    };
    

    Versi kompilator sebelumnya menerima ini, tetapi sekarang pengkompilasi memberikan kesalahan berikut:

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

    Untuk memperbaiki kesalahan, hapus kata kunci redundan mutable .

  • char_16_t dan char32_t

    Anda tidak dapat lagi menggunakan char16_t atau char32_t sebagai alias dalam typedef, karena jenis ini sekarang diperlakukan sebagai bawaan. Pengguna dan penulis pustaka umum untuk mendefinisikan char16_t dan char32_t sebagai alias dan uint16_tuint32_t, masing-masing.

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

    Untuk memperbarui kode Anda, hapus typedef deklarasi dan ganti nama pengidentifikasi lain yang bertabrakan dengan nama-nama ini.

  • Parameter templat non-jenis

    Kode tertentu yang melibatkan parameter templat non-jenis sekarang diperiksa dengan benar untuk kompatibilitas jenis saat Anda memberikan argumen templat eksplisit. Misalnya, kode berikut dikompilasi tanpa kesalahan di versi Visual Studio sebelumnya.

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

    Pengkompilasi saat ini memberikan kesalahan dengan benar, karena jenis parameter templat tidak cocok dengan argumen templat (parameter adalah penunjuk ke anggota const, tetapi fungsi f non-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'
    

    Untuk mengatasi kesalahan ini dalam kode Anda, pastikan bahwa jenis argumen templat yang Anda gunakan cocok dengan jenis parameter templat yang dideklarasikan.

  • __declspec(align)

    Pengkompilasi tidak lagi menerima __declspec(align) fungsi. Konstruksi ini selalu diabaikan, tetapi sekarang menghasilkan kesalahan kompilator.

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

    Untuk memperbaiki masalah ini, hapus __declspec(align) dari deklarasi fungsi. Karena tidak berpengaruh, menghapusnya tidak mengubah apa pun.

  • Penanganan pengecualian

    Ada beberapa perubahan pada penanganan pengecualian. Pertama, objek pengecualian harus dapat disalin atau bergerak. Kode berikut dikompilasi di Visual Studio 2013, tetapi tidak dikompilasi di Visual Studio 2015:

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

    Masalahnya adalah bahwa konstruktor salinan bersifat pribadi, sehingga objek tidak dapat disalin seperti yang terjadi dalam perjalanan normal menangani pengecualian. Hal yang sama berlaku ketika konstruktor salinan dinyatakan explicit.

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

    Untuk memperbarui kode Anda, pastikan bahwa konstruktor salinan untuk objek pengecualian Anda adalah public dan tidak ditandai explicit.

    Menangkap pengecualian berdasarkan nilai juga mengharuskan objek pengecualian dapat disalin. Kode berikut dikompilasi di Visual Studio 2013, tetapi tidak dikompilasi di Visual Studio 2015:

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

    Anda dapat memperbaiki masalah ini dengan mengubah jenis parameter untuk catch menjadi referensi.

    catch (D& d)
    {
    }
    
  • String literal diikuti oleh makro

    Kompiler sekarang mendukung literal yang ditentukan pengguna. Sebagai konsekuensinya, string harfiah diikuti oleh makro tanpa spasi yang mengintervensi ditafsirkan sebagai literal yang ditentukan pengguna, yang mungkin menghasilkan kesalahan atau hasil yang tidak terduga. Misalnya, di kompilator sebelumnya, kode berikut berhasil dikompilasi:

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

    Kompiler menafsirkan kode ini sebagai string harfiah "hello" diikuti oleh makro, yang diperluas ke "sana", dan kemudian dua literal string digabungkan menjadi satu. Di Visual Studio 2015, pengkompilasi menafsirkan urutan ini sebagai harfiah yang ditentukan pengguna, tetapi karena tidak ada yang cocok yang ditentukan pengguna secara harfiah _x , itu memberikan kesalahan.

    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?
    

    Untuk memperbaiki masalah ini, tambahkan spasi antara string literal dan makro.

  • Literal string yang berdekatan

    Demikian pula dengan sebelumnya, karena perubahan terkait dalam penguraian string, literal string yang berdekatan (baik literal string karakter lebar atau sempit) tanpa spasi putih ditafsirkan sebagai string tunggal yang digabungkan dalam rilis Visaul C++sebelumnya. Di Visual Studio 2015, Anda sekarang harus menambahkan spasi kosong di antara dua string. Misalnya, kode berikut harus diubah:

    char * str = "abc""def";
    

    Untuk memperbaiki masalah ini, tambahkan spasi di antara dua string:

    char * str = "abc" "def";
    
  • Penempatan baru dan hapus

    Perubahan telah dilakukan pada delete operator agar sesuai dengan standar C++14. Detail perubahan standar dapat ditemukan di Alokasi Berukuran C++. Perubahan menambahkan bentuk operator global delete yang mengambil parameter ukuran. Perubahan yang melanggar adalah bahwa jika Sebelumnya Anda menggunakan operator delete dengan tanda tangan yang sama (sesuai dengan operator baru penempatan), Anda akan menerima kesalahan kompilator (C2956, yang terjadi pada titik di mana penempatan baru digunakan, karena itulah posisi dalam kode di mana pengkompilasi mencoba mengidentifikasi operator pencocokan delete yang sesuai).

    Fungsi void operator delete(void *, size_t) ini adalah operator penghapusan penempatan yang sesuai dengan fungsi void * operator new(size_t, size_t) baru penempatan di C++11. Dengan dealokasi berukuran C++14, fungsi penghapusan ini sekarang merupakan fungsi dealokasi biasa (operator global delete ). Standar mengharuskan bahwa jika penggunaan penempatan baru mencari fungsi penghapusan yang sesuai dan menemukan fungsi dealokasi yang biasa, program akan terbentuk dengan tidak benar.

    Misalnya, kode Anda menentukan penempatan baru dan penghapusan penempatan:

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

    Masalah terjadi karena kecocokan dalam tanda tangan fungsi antara operator penghapusan penempatan yang telah Anda tentukan, dan operator berukuran delete global baru. Pertimbangkan apakah Anda dapat menggunakan jenis yang berbeda selain size_t untuk penempatan apa pun yang baru dan delete operator. Jenisnya size_ttypedef adalah compiler-dependent; ini adalah typedef untuk unsigned int di MSVC. Solusi yang baik adalah menggunakan jenis enumerasi seperti ini:

    enum class my_type : size_t {};
    

    Kemudian, ubah definisi penempatan Anda baru dan delete untuk menggunakan jenis ini sebagai argumen kedua alih-alih size_t. Anda juga harus memperbarui panggilan ke penempatan baru untuk meneruskan jenis baru (misalnya, dengan menggunakan static_cast<my_type> untuk mengonversi dari nilai bilangan bulat) dan memperbarui definisi dan delete untuk mentransmisikan kembali ke jenis bilangan new bulat. Anda tidak perlu menggunakan enum untuk ini; jenis kelas dengan size_t anggota juga akan berfungsi.

    Solusi alternatifnya adalah Anda mungkin dapat menghilangkan penempatan baru sama sekali. Jika kode Anda menggunakan penempatan baru untuk mengimplementasikan kumpulan memori di mana argumen penempatan adalah ukuran objek yang dialokasikan atau dihapus, maka fitur dealokasi berukuran mungkin cocok untuk mengganti kode kumpulan memori kustom Anda sendiri, dan Anda dapat menyingkirkan fungsi penempatan dan hanya menggunakan operator dua argumen delete Anda sendiri alih-alih fungsi penempatan.

    Jika Anda tidak ingin segera memperbarui kode, Anda dapat kembali ke perilaku lama dengan menggunakan opsi /Zc:sizedDealloc-pengkompilasi . Jika Anda menggunakan opsi ini, fungsi penghapusan dua argumen tidak ada dan tidak akan menyebabkan konflik dengan operator penghapusan penempatan Anda.

  • Anggota data union

    Anggota data dari serikat tidak dapat lagi memiliki jenis referensi. Kode berikut berhasil dikompilasi di Visual Studio 2013, tetapi menghasilkan kesalahan di Visual Studio 2015.

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

    Kode sebelumnya menghasilkan kesalahan berikut:

    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
    

    Untuk mengatasi masalah ini, ubah jenis referensi baik ke penunjuk atau nilai. Mengubah jenis menjadi penunjuk memerlukan perubahan dalam kode yang menggunakan bidang union. Mengubah kode menjadi nilai akan mengubah data yang disimpan dalam gabungan, yang memengaruhi bidang lain karena bidang dalam jenis gabungan berbagi memori yang sama. Tergantung pada ukuran nilai, nilai juga dapat mengubah ukuran serikat.

  • Serikat anonim sekarang lebih sesuai dengan standar. Versi kompilator sebelumnya menghasilkan konstruktor dan destruktor eksplisit untuk serikat anonim. Fungsi yang dihasilkan kompilator ini dihapus di Visual Studio 2015.

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

    Kode sebelumnya menghasilkan kesalahan berikut di 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
    

    Untuk mengatasi masalah ini, berikan definisi Anda sendiri tentang konstruktor dan/atau destruktor.

    struct S
    {
        // Provide a default constructor by adding an empty function body.
        S() {}
    };
    
    union
    {
        struct
        {
            S s;
        };
    } u;
    
  • Serikat dengan struktur anonim

    Untuk menyesuaikan dengan standar, perilaku runtime telah berubah untuk anggota struktur anonim dalam serikat. Konstruktor untuk anggota struktur anonim dalam serikat tidak lagi secara implisit dipanggil ketika serikat tersebut dibuat. Selain itu, destruktor untuk anggota struktur anonim dalam serikat tidak lagi secara implisit dipanggil ketika penyatuan keluar dari cakupan. Pertimbangkan kode berikut, di mana union U berisi struktur anonim yang berisi struktur anggota bernama S yang memiliki destruktor.

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

    Di Visual Studio 2013, konstruktor untuk S dipanggil saat penyatuan dibuat, dan destruktor untuk S dipanggil ketika tumpukan untuk fungsi f dibersihkan. Tetapi di Visual Studio 2015, konstruktor dan destruktor tidak dipanggil. Pengkompilasi memberikan peringatan tentang perubahan perilaku ini.

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

    Untuk memulihkan perilaku asli, beri nama struktur anonim. Perilaku runtime struktur non-anonim sama, terlepas dari versi pengompilasi.

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

    Atau, coba pindahkan kode konstruktor dan destruktor ke fungsi baru, dan tambahkan panggilan ke fungsi-fungsi ini dari konstruktor dan destruktor untuk serikat.

    #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;
    }
    
  • Resolusi templat

    Perubahan telah dilakukan pada resolusi nama untuk templat. Di C++, ketika mempertimbangkan kandidat untuk resolusi nama, bisa jadi satu atau beberapa nama dipertimbangkan karena potensi kecocokan menghasilkan instansiasi templat yang tidak valid. Instansiasi yang tidak valid ini biasanya tidak menyebabkan kesalahan kompilator, prinsip yang dikenal sebagai SFINAE (Kegagalan Penggantian Bukan Kesalahan).

    Sekarang, jika SFINAE mengharuskan pengkompilasi untuk membuat instans spesialisasi templat kelas, maka kesalahan apa pun yang terjadi selama proses ini adalah kesalahan kompilator. Di versi sebelumnya, pengkompilasi akan mengabaikan kesalahan tersebut. Sebagai contoh, perhatikan kode berikut:

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

    Jika Anda mengkompilasi dengan pengkompilasi saat ini, Anda mendapatkan kesalahan berikut:

    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
    ]
    

    Ini karena pada titik pemanggilan pertama is_base_of kelas D belum ditentukan.

    Dalam hal ini, perbaikannya adalah tidak menggunakan sifat jenis tersebut sampai kelas telah ditentukan. Jika Anda memindahkan definisi B dan D ke awal file kode, kesalahan akan diatasi. Jika definisi berada dalam file header, periksa urutan pernyataan sertakan untuk file header untuk memastikan bahwa definisi kelas apa pun dikompilasi sebelum templat bermasalah digunakan.

  • Menyalin konstruktor

    Di Visual Studio 2013 dan Visual Studio 2015, kompilator menghasilkan konstruktor salinan untuk kelas jika kelas tersebut memiliki konstruktor pemindahan yang ditentukan pengguna tetapi tidak ada konstruktor salinan yang ditentukan pengguna. Di Dev14, konstruktor salinan yang dihasilkan secara implisit ini juga ditandai "= hapus".

  • utama yang dinyatakan sebagai ekstern "C" sekarang memerlukan jenis pengembalian.

    Kode berikut sekarang menghasilkan C4430.

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

    Untuk memperbaiki kesalahan, tambahkan jenis pengembalian:

    extern "C" int __cdecl main(){} // OK
    
  • typename tidak diperbolehkan dalam penginisialisasi anggota

    Kode berikut sekarang menghasilkan C2059:

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

    Untuk memperbaiki kesalahan, hapus typename dari penginisialisasi:

    S1() : T::type() // OK
    ...
    
  • Kelas penyimpanan pada spesialisasi eksplisit diabaikan.

    Dalam kode berikut, penentu kelas penyimpanan statis diabaikan

    template <typename T>
    void myfunc(T h)
    {
    }
    
    template<>
    static void myfunc(double h) // static is ignored
    {
    }
    
  • Konstanta yang digunakan dalam static_assert di dalam templat kelas akan selalu gagal.

    Kode berikut menyebabkan static_assert selalu gagal:

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

    Untuk mengatasi masalah ini, bungkus nilai dalam 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
    
  • Aturan yang diberlakukan untuk deklarasi penerusan. (Hanya berlaku untuk C.)

    Kode berikut sekarang menghasilkan C2065:

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

    Untuk memperbaiki masalah ini, tambahkan deklarasi penerusan yang tepat:

    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);
    
  • Penegakan jenis penunjuk fungsi yang lebih konsisten

    Kode berikut sekarang menghasilkan C2197:

    typedef int(*F1)(int);
    typedef int(*F2)(int, int);
    
    void func(F1 f, int v1, int v2)
    {
        f(v1, v2); // C2197
    }
    
  • Panggilan ambigu ke fungsi yang kelebihan beban

    Kode berikut sekarang menghasilkan C266: 'N::bind': panggilan ambigu ke fungsi yang kelebihan beban

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

    Untuk memperbaiki kesalahan, Anda dapat sepenuhnya memenuhi syarat panggilan ke bind: N::bind(...). Namun, jika perubahan ini dimanifestasikan melalui pengidentifikasi yang tidak dinyatakan (C2065), maka mungkin tepat untuk memperbaikinya dengan using deklarasi sebagai gantinya.

    Pola ini sering terjadi dengan ComPtr dan jenis lain di Microsoft::WRL namespace layanan.

  • Perbaiki alamat yang salah dari

    Kode berikut sekarang menghasilkan C2440: '=': tidak dapat mengonversi dari 'type *' ke 'type'. Untuk memperbaiki kesalahan, ubah &(ketik) menjadi (type) dan (&f()) menjadi (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());
    }
    
  • String literal adalah array konstanta

    Kode berikut sekarang menghasilkan C2664: 'void f(void )': tidak dapat mengonversi argumen 1 dari 'const char ()[2]' ke 'void *'

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

    Untuk memperbaiki kesalahan, ubah jenis parameter fungsi menjadi const void*, atau ubah isi h agar terlihat seperti contoh ini:

    void h(void)
    {
        char name[] = __FUNCTION__;
        f( name);
        void *p = &"";
    }
    
  • String UDL C++11

    Kode berikut sekarang menghasilkan kesalahan C3688: akhiran harfiah 'L' yang tidak valid; operator literal atau operator literal template 'operator ""L' tidak ditemukan

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

    Untuk memperbaiki kesalahan, ubah kode untuk menambahkan spasi:

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

    Dalam contoh di atas, MACRO tidak lagi diurai sebagai dua token (string diikuti oleh makro). Sekarang diurai sebagai UDL token tunggal. Hal yang sama berlaku untuk L""L", yang diurai sebelumnya sebagai L"" dan L"", dan sekarang diurai sebagai L""L dan "".

    Aturan perangkaian string juga dibawa sesuai dengan standar, yang berarti L"a" "b" setara dengan L"ab". Edisi Visual Studio sebelumnya tidak menerima perangkaian string dengan lebar karakter yang berbeda.

  • Karakter kosong C++11 dihapus

    Kode berikut sekarang menghasilkan kesalahan C2137: konstanta karakter kosong

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

    Untuk memperbaiki kesalahan, ubah kode untuk membuat null eksplisit:

    bool check(wchar_t c){
        return c == L'\0';
    }
    
  • Pengecualian MFC tidak dapat ditangkap oleh nilai karena tidak dapat disalin

    Kode berikut dalam aplikasi MFC sekarang menyebabkan kesalahan C2316: 'D': tidak dapat ditangkap karena konstruktor destruktor dan/atau salinan tidak dapat diakses atau dihapus

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

    Untuk memperbaiki kode, Anda dapat mengubah blok tangkapan menjadi catch (const D &) tetapi solusi yang lebih baik biasanya menggunakan makro MFC TRY/CATCH.

  • alignof sekarang menjadi kata kunci

    Kode berikut sekarang menghasilkan kesalahan C2332: 'class': nama tag yang hilang. Untuk memperbaiki kode, Anda harus mengganti nama kelas atau, jika kelas melakukan pekerjaan yang sama dengan alignof, cukup ganti kelas dengan kata kunci baru.

    class alignof{}
    
  • constexpr sekarang menjadi kata kunci

    Kode berikut sekarang menghasilkan kesalahan C2059: kesalahan sintaks: ')'. Untuk memperbaiki kode, Anda harus mengganti nama fungsi atau nama variabel apa pun yang disebut constexpr.

    int constexpr() {return 1;}
    
  • Jenis movable tidak dapat menjadi const

    Ketika fungsi mengembalikan jenis yang dimaksudkan untuk dipindahkan, jenis pengembaliannya tidak boleh const.

  • Konstruktor salinan yang dihapus

    Kode berikut sekarang menghasilkan C2280 'S::S(S &)': mencoba mereferensikan fungsi yang dihapus:

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

    Untuk memperbaiki kesalahan, gunakan inisialisasi langsung untuk S2:

    struct S{
        S(int, int);
        S(const S&) = delete;
        S(S&&) = delete;
    };
    
    S s2 = {2,3}; //OK
    
  • Konversi ke penunjuk fungsi hanya dihasilkan ketika tidak ada pengambilan lambda

    Kode berikut menghasilkan C2664 di Visual Studio 2015.

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

    Untuk memperbaiki kesalahan, hapus = dari daftar pengambilan.

  • Panggilan ambigu yang melibatkan operator konversi

    Kode berikut sekarang menghasilkan kesalahan C2440: 'type cast': tidak dapat mengonversi dari 'S2' ke 'S1':

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

    Untuk memperbaiki kesalahan, panggil operator konversi secara eksplisit:

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

    Kode berikut sekarang menghasilkan kesalahan C2593: 'operator =' ambigu:

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

    Untuk memperbaiki kesalahan, panggil operator konversi secara eksplisit:

    void f(S1 *p, S2 s)
    {
        *p = s.operator S1&();
    }
    
  • Memperbaiki inisialisasi salinan yang tidak valid dalam inisialisasi anggota data non-statis (NSDMI)

    Kode berikut sekarang menghasilkan kesalahan C2664: 'S1::S1(S1 &&)': tidak dapat mengonversi argumen 1 dari 'bool' ke 'const S1 &':

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

    Untuk memperbaiki kesalahan, gunakan inisialisasi langsung:

    struct S2 {
    S1 s1{true}; // OK
    };
    
  • Mengakses konstruktor di dalam pernyataan decltype

    Kode berikut sekarang menghasilkan C2248: 'S::S': tidak dapat mengakses anggota privat yang dideklarasikan di kelas 'S':

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

    Untuk memperbaiki kesalahan, tambahkan deklarasi teman untuk S2 di S:

    class S {
        S();
        friend class S2; // Make S2 a friend
    public:
        int i;
    };
    
  • Ctor default lambda dihapus secara implisit

    Kode berikut sekarang menghasilkan kesalahan C3497: Anda tidak dapat membuat instans lambda:

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

    Untuk memperbaiki kesalahan, hapus kebutuhan konstruktor default untuk dipanggil. Jika lambda tidak menangkap apa pun, maka lambda dapat dilemparkan ke penunjuk fungsi.

  • Lambdas dengan operator penugasan yang dihapus

    Kode berikut sekarang menghasilkan kesalahan 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);
    }
    

    Untuk memperbaiki kesalahan, ganti lambda dengan kelas functor atau hapus kebutuhan untuk menggunakan operator penugasan.

  • Mencoba memindahkan objek dengan konstruktor salinan yang dihapus

    Kode berikut sekarang menghasilkan kesalahan C2280: 'moveable::moveable(const moveable &)': mencoba mereferensikan fungsi yang dihapus

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

    Untuk memperbaiki kesalahan, gunakan std::move sebagai gantinya:

    S(moveable && m) :
        m_m(std::move(m))
    
  • Kelas lokal tidak dapat mereferensikan kelas lokal lain yang ditentukan nanti dalam fungsi yang sama

    Kode berikut sekarang menghasilkan kesalahan C2079: 's' menggunakan struct 'main::S2' yang tidak ditentukan

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

    Untuk memperbaiki kesalahan, pindah ke atas definisi S2:

    int main()
    {
        struct S2 { //moved up
        };
    
    struct S1 {
        void f() {
            S2 s;
            }
        };
    }
    
  • Tidak dapat memanggil ctor dasar yang dilindungi dalam isi ctor turunan.

    Kode berikut sekarang menghasilkan kesalahan C2248: 'S1::S1': tidak dapat mengakses anggota yang dilindungi yang dideklarasikan di kelas 'S1'

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

    Untuk memperbaiki kesalahan, hapus S2 panggilan ke S1() dari konstruktor dan jika perlu letakkan di fungsi lain.

  • {} mencegah konversi ke penunjuk

    Kode berikut sekarang menghasilkan C2439 'S::p': anggota tidak dapat diinisialisasi

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

    Untuk memperbaiki kesalahan, hapus kurung kurawal dari sekitar 0 atau gunakan nullptr sebagai gantinya, seperti yang ditunjukkan dalam contoh ini:

    struct S {
        S() : p(nullptr) {}
        void *p;
    };
    
  • Definisi makro dan penggunaan yang salah dengan tanda kurung

    Contoh berikut sekarang menghasilkan kesalahan C2008: ';': tidak terduga dalam definisi makro

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

    Untuk memperbaiki masalah, ubah baris atas menjadi #define A();

    Kode berikut menghasilkan kesalahan C2059: kesalahan sintaks: ')'

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

    Untuk memperbaiki kode, hapus spasi antara A dan ().

    Kode berikut menghasilkan kesalahan C2091: fungsi mengembalikan fungsi:

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

    Untuk memperbaiki kesalahan, hapus tanda kurung setelah DECLARE di S: DECLARE;.

    Kode berikut menghasilkan kesalahan C2062: ketik 'int' tidak terduga

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

    Untuk memperbaiki masalah, tentukan A seperti ini:

    #define A int
    
  • Paren tambahan dalam deklarasi

    Kode berikut menghasilkan kesalahan C2062: ketik 'int' tidak terduga

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

    Untuk memperbaiki kesalahan, hapus tanda kurung di sekitar j. Jika tanda kurung diperlukan untuk kejelasan, maka gunakan typedef.

  • Konstruktor dan __declspec yang dihasilkan kompilator (dapat dihidupkan)

    Di Visual Studio 2015, ada peningkatan kemungkinan bahwa konstruktor inline yang dihasilkan kompilator kelas abstrak dengan kelas dasar virtual dapat mengekspos penggunaan __declspec(novtable) yang tidak tepat ketika digunakan dalam kombinasi dengan __declspec(dllimport).

  • otomatis memerlukan ekspresi tunggal dalam direct-list-initialization

    Kode berikut sekarang menghasilkan kesalahan C3518: 'testPositions': dalam konteks direct-list-initialization jenis untuk 'auto' hanya dapat disimpulkan dari ekspresi penginisialisasi tunggal

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

    Untuk memperbaiki kesalahan, salah satu kemungkinannya adalah menginisialisasi testPositions sebagai berikut:

    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}
    };
    
  • Memeriksa jenis vs. pointer ke jenis untuk is_convertible

    Kode berikut sekarang menyebabkan pernyataan statis gagal.

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

    Untuk memperbaiki kesalahan, ubah static_assert sehingga membandingkan pointer dengan D dan B2:

    static_assert(std::is_convertible<D*, B2*>::value, "fail");
    
  • deklarasi __declspec(dapat diubah) harus konsisten

    __declspec deklarasi harus konsisten di semua pustaka. Kode berikut sekarang akan menghasilkan pelanggaran aturan satu definisi (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;
    

Penyempurnaan Kesuaian di Pembaruan 1

  • Kelas dasar virtual privat dan pewarisan tidak langsung

    Versi kompilator sebelumnya memungkinkan kelas turunan untuk memanggil fungsi anggota dari kelas dasar turunannya secara private virtual tidak langsung. Perilaku lama ini salah dan tidak sesuai dengan standar C++. Kompiler tidak lagi menerima kode yang ditulis dengan cara ini, dan mengeluarkan kesalahan kompilator C2280 sebagai hasilnya.

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

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

    - atau -

    class base;  // as above
    
    class middle : private virtual base {};
    class top : public virtual middle, private virtual bottom {};
    
    void destroy(top *p)
    {
        delete p;
    }
    
  • Operator baru yang kelebihan beban dan penghapusan operator

    Versi kompilator sebelumnya memungkinkan operator non-anggota menghapus operator baru dan non-anggota untuk dinyatakan statis, dan dideklarasikan dalam namespace selain namespace global. Perilaku lama ini menciptakan risiko bahwa program tidak akan memanggil new implementasi atau delete operator yang dimaksudkan programmer, menghasilkan perilaku runtime yang buruk diam-diam. Pengkompilasi tidak lagi menerima kode yang ditulis dengan cara ini dan mengeluarkan kesalahan pengkompilasi C2323 sebagai gantinya.

    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.
    

    Contoh (sebelumnya)

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

    Contoh (setelah)

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

    Selain itu, meskipun pengkompilasi tidak memberikan diagnostik tertentu, operator new sebaris dianggap tidak terbentuk.

  • Memanggil ' operator type()' (konversi yang ditentukan pengguna) pada jenis non-kelas

    Versi kompilator sebelumnya memungkinkan ' operator type()' untuk dipanggil pada jenis non-kelas sambil mengabaikannya secara diam-diam. Perilaku lama ini menciptakan risiko pembuatan kode buruk senyap, yang mengakibatkan perilaku runtime yang tidak dapat diprediksi. Kompilator tidak lagi menerima kode yang ditulis dengan cara ini dan mengeluarkan kesalahan kompilator C2228 sebagai gantinya.

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

    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'
    }
    
  • Nama jenis redundan dalam penentu jenis yang dijabarkan

    Versi kompilator sebelumnya diizinkan typename dalam penentu jenis yang dijabarkan, tetapi kode yang ditulis dengan cara ini secara semantik salah. Pengkompilasi tidak lagi menerima kode yang ditulis dengan cara ini dan mengeluarkan kesalahan pengkompilasi C3406 sebagai gantinya.

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

    Contoh (sebelumnya)

    template <typename class T>
    class container;
    

    Contoh (setelah)

    template <class T>  // alternatively, could be 'template <typename T>'; 'typename' is not elaborating a type specifier in this case
    class container;
    
  • Mengetik pengurangan array dari daftar penginisialisasi

    Versi kompilator sebelumnya tidak mendukung pengurangan jenis array dari daftar penginisialisasi. Pengompilasi sekarang mendukung bentuk pengurangan jenis ini dan, sebagai hasilnya, panggilan ke templat fungsi menggunakan daftar penginisialisasi sekarang mungkin ambigu atau kelebihan beban yang berbeda mungkin dipilih daripada di versi kompilator sebelumnya. Untuk mengatasi masalah ini, program sekarang harus secara eksplisit menentukan kelebihan beban yang dimaksudkan programmer.

    Ketika perilaku baru ini menyebabkan resolusi kelebihan beban untuk mempertimbangkan kandidat tambahan yang sama baiknya dengan kandidat historis, panggilan menjadi ambigu dan kompilator mengeluarkan kesalahan kompilator C2668 sebagai hasilnya.

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

    Contoh 1: Panggilan ambigu ke fungsi kelebihan beban (sebelumnya)

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

    Contoh 1: panggilan ambigu ke fungsi yang kelebihan beban (setelah)

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

    Ketika perilaku baru ini menyebabkan resolusi kelebihan beban untuk mempertimbangkan kandidat tambahan yang lebih cocok daripada kandidat historis, panggilan diselesaikan secara tidak ambigu ke kandidat baru, menyebabkan perubahan perilaku program yang mungkin berbeda dari programmer yang dimaksudkan.

    Contoh 2: perubahan resolusi kelebihan beban (sebelumnya)

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

    Contoh 2: perubahan resolusi kelebihan beban (setelah)

    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 });
    }
    
  • Pemulihan peringatan pernyataan pengalihan

    Versi kompilator sebelumnya menghapus beberapa peringatan yang terkait dengan switch pernyataan; peringatan ini sekarang telah dipulihkan. Kompiler sekarang mengeluarkan peringatan yang dipulihkan, dan peringatan yang terkait dengan kasus tertentu (termasuk kasus default) sekarang dikeluarkan pada baris yang berisi kasus yang menyinggung, bukan pada baris terakhir pernyataan switch. Akibat dari sekarang mengeluarkan peringatan tersebut pada baris yang berbeda dari di masa lalu, peringatan yang sebelumnya ditekan dengan menggunakan #pragma warning(disable:####) mungkin tidak lagi ditekan seperti yang dimaksudkan. Untuk menekan peringatan ini seperti yang dimaksudkan, mungkin perlu untuk memindahkan #pragma warning(disable:####) arahan ke garis di atas kasus pertama yang menyinggung. Berikut ini adalah peringatan yang dipulihkan:

    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
    

    Contoh C4063 (sebelumnya)

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

    Contoh C4063 (setelah)

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

    Contoh peringatan lain yang dipulihkan disediakan dalam dokumentasinya.

  • #include: penggunaan penentu direktori induk '..' dalam nama jalur (hanya mempengaruhi /Wall/WX)

    Versi kompilator sebelumnya tidak mendeteksi penggunaan penentu direktori induk '..' dalam nama jalur arahan #include . Kode yang ditulis dengan cara ini biasanya dimaksudkan untuk menyertakan header yang ada di luar proyek dengan salah menggunakan jalur relatif proyek. Perilaku lama ini menciptakan risiko bahwa program dapat dikompilasi dengan menyertakan file sumber yang berbeda dari programmer yang dimaksudkan, atau bahwa jalur relatif ini tidak akan portabel ke lingkungan build lainnya. Pengkompilasi sekarang mendeteksi dan memberi tahu pemrogram kode yang ditulis dengan cara ini dan mengeluarkan peringatan kompilator opsional C4464, jika diaktifkan.

    warning C4464: relative include path contains '..'
    

    Contoh (sebelumnya)

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

    Contoh (setelah)

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

    Selain itu, meskipun pengkompilasi tidak memberikan diagnostik tertentu, kami juga menyarankan agar penentu direktori induk ".." tidak boleh digunakan untuk menentukan direktori sertakan proyek Anda.

  • #pragma optimize() memperluas akhir file header sebelumnya (hanya memengaruhi /Wall/WX)

    Versi kompilator sebelumnya tidak mendeteksi perubahan pada pengaturan bendera pengoptimalan yang lolos dari file header yang disertakan dalam unit terjemahan. Kompilator sekarang mendeteksi dan memberi tahu pemrogram kode yang ditulis dengan cara ini dan mengeluarkan peringatan kompilator opsional C4426 di lokasi yang menyinggung #include, jika diaktifkan. Peringatan ini hanya dikeluarkan jika perubahan bertentangan dengan bendera pengoptimalan yang diatur oleh argumen baris perintah ke pengkompilasi.

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

    // 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"
    
  • Peringatan #pragma yang tidak cocok(push) dan peringatan #pragma(pop) (hanya memengaruhi /Wall/WX)

    Versi kompilator sebelumnya tidak mendeteksi #pragma warning(push) perubahan status dipasangkan dengan #pragma warning(pop) perubahan status dalam file sumber yang berbeda, yang jarang dimaksudkan. Perilaku lama ini menciptakan risiko bahwa program akan dikompilasi dengan serangkaian peringatan yang berbeda yang diaktifkan dari programmer yang dimaksudkan, mungkin mengakibatkan perilaku runtime yang buruk senyap. Pengkompilasi sekarang mendeteksi dan memberi tahu pemrogram kode yang ditulis dengan cara ini dan mengeluarkan peringatan kompilator opsional C5031 di lokasi pencocokan #pragma warning(pop), jika diaktifkan. Peringatan ini mencakup catatan yang mereferensikan lokasi peringatan #pragma yang sesuai(push).

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

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

    Meskipun jarang, kode yang ditulis dengan cara ini terkadang disengaja. Kode yang ditulis dengan cara ini sensitif terhadap perubahan #include secara berurutan; jika memungkinkan, sebaiknya file kode sumber mengelola status peringatan dengan cara mandiri.

  • Peringatan #pragma tidak cocok(push) (hanya memengaruhi /Wall/WX)

    Versi kompilator sebelumnya tidak mendeteksi perubahan status yang tidak cocok #pragma warning(push) di akhir unit terjemahan. Pengkompilasi sekarang mendeteksi dan memberi tahu pemrogram kode yang ditulis dengan cara ini dan mengeluarkan peringatan kompilator opsional C5032 di lokasi yang tidak cocok #pragma warning(push), jika diaktifkan. Peringatan ini hanya dikeluarkan jika tidak ada kesalahan kompilasi di unit terjemahan.

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

    // 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)
    
  • Peringatan tambahan mungkin dikeluarkan sebagai akibat dari peningkatan #pragma pelacakan status peringatan

    Versi kompilator sebelumnya melacak perubahan status peringatan #pragma tidak cukup baik untuk mengeluarkan semua peringatan yang dimaksudkan. Perilaku ini menciptakan risiko bahwa peringatan tertentu akan secara efektif ditekan dalam keadaan yang berbeda dari programmer yang dimaksudkan. Pengompilasi sekarang melacak #pragma warning status dengan lebih kuat -- terutama terkait #pragma warning dengan perubahan status di dalam templat -- dan secara opsional mengeluarkan peringatan baru C5031 dan C5032, yang dimaksudkan untuk membantu programmer menemukan penggunaan #pragma warning(push) dan #pragma warning(pop)yang tidak diinginkan.

    Sebagai akibat dari peningkatan #pragma warning pelacakan perubahan status, peringatan yang sebelumnya salah ditekan atau peringatan yang terkait dengan masalah yang sebelumnya salah didiagnosis mungkin sekarang dikeluarkan.

  • Peningkatan identifikasi kode yang tidak dapat dijangkau

    Pustaka Standar C++ mengubah dan meningkatkan kemampuan untuk panggilan fungsi sebaris melalui versi kompilator sebelumnya mungkin memungkinkan pengkompilasi untuk membuktikan bahwa kode tertentu sekarang tidak dapat dijangkau. Perilaku baru ini dapat menghasilkan instans peringatan C4720 baru dan lebih sering dikeluarkan.

    warning C4720: unreachable code
    

    Dalam banyak kasus, peringatan ini mungkin hanya dikeluarkan saat mengkompilasi dengan pengoptimalan diaktifkan, karena pengoptimalan dapat menginline lebih banyak panggilan fungsi, menghilangkan kode redundan, atau memungkinkan untuk menentukan bahwa kode tertentu tidak dapat dijangkau. Kami telah mengamati bahwa instans baru peringatan C4720 sering terjadi di blok try/catch , terutama dalam kaitannya dengan penggunaan std::find.

    Contoh (sebelumnya)

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

    Contoh (setelah)

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

Penyempurnaan Kesuaian di Pembaruan 2

  • Peringatan dan kesalahan tambahan mungkin dikeluarkan sebagai akibat dari dukungan parsial untuk ekspresi SFINAE

    Versi kompilator sebelumnya tidak mengurai jenis ekspresi tertentu di dalam decltype penentu karena kurangnya dukungan untuk ekspresi SFINAE. Perilaku lama ini salah dan tidak sesuai dengan standar C++. Kompilator sekarang mengurai ekspresi ini dan memiliki dukungan parsial untuk ekspresi SFINAE karena peningkatan kesesuaian yang sedang berlangsung. Akibatnya, pengkompilasi sekarang mengeluarkan peringatan dan kesalahan yang ditemukan dalam ekspresi yang versi kompiler sebelumnya tidak diurai.

    Ketika perilaku baru ini mengurai decltype ekspresi yang menyertakan jenis yang belum dinyatakan, kompilator mengeluarkan kesalahan kompilator C2039 sebagai hasilnya.

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

    Contoh 1: penggunaan jenis yang tidak dinyatakan (sebelumnya)

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

    Contoh 1 (setelah)

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

    Ketika perilaku baru ini menguraikan decltype ekspresi yang kehilangan penggunaan typename kata kunci yang diperlukan untuk menentukan bahwa nama dependen adalah jenis, pengkompilasi mengeluarkan peringatan kompilator C4346 bersama dengan kesalahan kompilator 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'
    

    Contoh 2: nama dependen bukan jenis (sebelumnya)

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

    Contoh 2 (setelah)

    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> ()));
    };
    
  • volatilevariabel anggota mencegah konstruktor dan operator penugasan yang ditentukan secara implisit

    Versi kompilator sebelumnya memungkinkan kelas yang memiliki volatile variabel anggota untuk memiliki konstruktor salin/pindah default dan operator penugasan salin/pindah default yang dibuat secara otomatis. Perilaku lama ini salah dan tidak sesuai dengan standar C++. Pengkompilasi sekarang mempertimbangkan kelas yang memiliki volatile variabel anggota untuk memiliki operator konstruksi dan penugasan yang tidak sepele, yang mencegah implementasi default operator ini dihasilkan secara otomatis. Ketika kelas tersebut adalah anggota serikat pekerja (atau serikat anonim di dalam kelas), konstruktor salin/pindah dan operator penetapan salin/pindah dari serikat pekerja (atau kelas yang berisi serikat anonim) akan secara implisit didefinisikan sebagai dihapus. Mencoba membangun atau menyalin serikat (atau kelas yang berisi serikat anonim) tanpa secara eksplisit mendefinisikannya adalah kesalahan dan kompilator mengeluarkan kesalahan kompilator C2280 sebagai hasilnya.

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

    Contoh (sebelumnya)

    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
    

    Contoh (setelah)

    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
    
  • Fungsi anggota statis tidak mendukung kualifikasi cv.

    Versi Visual Studio 2015 sebelumnya memungkinkan fungsi anggota statis memiliki kualifikasi cv. Perilaku ini disebabkan oleh regresi di Visual Studio 2015 dan Visual Studio 2015 Update 1; Visual Studio 2013 dan versi sebelumnya dari compiler menolak kode yang ditulis dengan cara ini. Perilaku Visual Studio 2015 dan Visual Studio 2015 Update 1 salah dan tidak sesuai dengan standar C++. Visual Studio 2015 Update 2 menolak kode yang ditulis dengan cara ini dan mengeluarkan kesalahan kompilator C2511 sebagai gantinya.

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

    Contoh (sebelumnya)

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

    Contoh(setelah)

    struct A
    {
        static void func();
    };
    
    void A::func() {}  // removed const
    
  • Deklarasi penerusan enum tidak diizinkan dalam kode WinRT (hanya mempengaruhi /ZW)

    Kode yang dikompilasi untuk Windows Runtime (WinRT) tidak memungkinkan enum jenis untuk diteruskan dideklarasikan, mirip dengan ketika kode C++ terkelola dikompilasi untuk .Net Framework menggunakan /clr sakelar pengkompilasi. Perilaku ini memastikan bahwa ukuran enumerasi selalu diketahui dan dapat diproyeksikan dengan benar ke sistem jenis WinRT. Pengkompilasi menolak kode yang ditulis dengan cara ini dan mengeluarkan kesalahan kompilator C2599 bersama dengan kesalahan kompilator C3197.

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

              // forward declaration of CustomEnum removed
    namespace A {
        public enum class CustomEnum : int32
        {
            Value1
        };
    }
    
    public ref class Component sealed
    {
    public:
        CustomEnum f()
        {
            return CustomEnum::Value1;
        }
    };
    
  • Operator non-anggota yang kelebihan beban baru dan penghapusan operator mungkin tidak dinyatakan sebaris (Tingkat 1 (/W1) secara default)

    Versi kompilator sebelumnya tidak mengeluarkan peringatan ketika operator non-anggota baru dan fungsi penghapusan operator dinyatakan sebaris. Kode yang ditulis dengan cara ini tidak terbentuk buruk (tidak diperlukan diagnostik) dan dapat menyebabkan masalah memori yang diakibatkan oleh operator baru dan penghapusan yang tidak cocok (terutama ketika digunakan bersama dengan dealokasi berukuran) yang dapat sulit didiagnosis. Kompilator sekarang mengeluarkan peringatan kompilator C4595 untuk membantu mengidentifikasi kode yang ditulis dengan cara ini.

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

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

    Memperbaiki kode yang ditulis dengan cara ini mungkin mengharuskan definisi operator dipindahkan dari file header dan ke file sumber yang sesuai.

Penyempurnaan Kesuaian di Pembaruan 3

  • std::is_convertable sekarang mendeteksi penugasan mandiri (pustaka standar)

    Versi sebelumnya dari std::is_convertable type-trait tidak mendeteksi penetapan sendiri jenis kelas dengan benar saat konstruktor salinannya dihapus atau privat. Sekarang, std::is_convertable<>::value diatur dengan benar ke false saat diterapkan ke jenis kelas dengan konstruktor salinan yang dihapus atau privat.

    Tidak ada diagnostik kompilator yang terkait dengan perubahan ini.

    Contoh

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

    Dalam versi compiler sebelumnya, pernyataan statis di bagian bawah contoh ini lulus karena std::is_convertable<>::value salah diatur ke true. Sekarang, std::is_convertable<>::value diatur dengan benar ke false, menyebabkan pernyataan statis gagal.

  • Salinan sepele default atau dihapus dan memindahkan konstruktor menghormati penentu akses

    Versi kompilator sebelumnya tidak memeriksa penentu akses salinan sepele default atau dihapus dan memindahkan konstruktor sebelum memungkinkan mereka dipanggil. Perilaku lama ini salah dan tidak sesuai dengan standar C++. Dalam beberapa kasus, perilaku lama ini menciptakan risiko pembuatan kode buruk senyap, yang mengakibatkan perilaku runtime yang tidak dapat diprediksi. Pengkompilasi sekarang memeriksa penentu akses salinan sepele default atau dihapus dan memindahkan konstruktor untuk menentukan apakah konstruktor dapat dipanggil, dan jika tidak, mengeluarkan peringatan kompilator C2248 sebagai hasilnya.

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

    Contoh (sebelumnya)

    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
    }
    

    Contoh (setelah)

    class S {
    public:
        S() = default;
    private:
        S(const S&) = default;
    };
    
    void f(const S&);  // pass S by reference
    
    int main()
    {
        S s;
        f(s);
    }
    
  • Penghentian dukungan kode ATL yang diatribusikan (Tingkat 1 (/W1) secara default)

    Versi sebelumnya dari pengkompilasi yang didukung mengaitkan kode ATL. Sebagai fase berikutnya menghapus dukungan untuk kode ATL atribut yang dimulai di Visual Studio 2008, kode ATL yang diatribusikan telah ditolak. Kompilator sekarang mengeluarkan peringatan kompilator C4467 untuk membantu mengidentifikasi jenis kode yang tidak digunakan lagi ini.

    warning C4467: Usage of ATL attributes is deprecated
    

    Jika Anda ingin terus menggunakan kode ATL yang diatribusikan hingga dukungan dihapus dari pengkompilasi, Anda dapat menonaktifkan peringatan ini dengan meneruskan /Wv:18 argumen baris perintah atau /wd:4467 ke pengkompilasi, atau dengan menambahkan #pragma warning(disable:4467) dalam kode sumber Anda.

    Contoh 1 (sebelumnya)

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

    Contoh 1 (setelah)

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

    Terkadang Anda mungkin memerlukan atau ingin membuat file IDL untuk menghindari penggunaan atribut ATL yang tidak digunakan lagi, seperti dalam contoh kode di bawah ini

    Contoh 2 (sebelumnya)

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

    Pertama, buat file *.idl; file vc140.idl yang dihasilkan dapat digunakan untuk mendapatkan file *.idl yang berisi antarmuka dan anotasi.

    Selanjutnya, tambahkan langkah MIDL ke build Anda untuk memastikan bahwa definisi antarmuka C++ dihasilkan.

    Contoh 2 IDL (setelah)

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

    Kemudian, gunakan ATL langsung dalam file implementasi, seperti dalam contoh kode di bawah ini.

    Contoh 2 Implementasi (setelah)

    #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()
    };
    
  • File header (PCH) yang telah dikommpilasikan sebelumnya dan direktif #include yang tidak cocok (hanya memengaruhi /Wall/WX)

    Versi kompilator sebelumnya menerima direktif yang tidak cocok #include dalam file sumber antara -Yc dan -Yu kompilasi saat menggunakan file header (PCH) yang telah dikompilasi sebelumnya. Kode yang ditulis dengan cara ini tidak lagi diterima oleh pengkompilasi. Kompilator sekarang mengeluarkan peringatan kompilator CC4598 untuk membantu mengidentifikasi direktif yang tidak cocok #include saat menggunakan file PCH.

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

    Contoh (sebelumnya):

    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"
    

    Contoh (setelah)

    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"
    
  • File header (PCH) yang telah dikompresi dan tidak cocok menyertakan direktori (hanya memengaruhi /Wall/WX)

    Versi kompilator sebelumnya yang diterima tidak cocok termasuk argumen baris perintah direktori (-I) ke kompilator antara -Yc dan -Yu kompilasi saat menggunakan file header (PCH) yang telah dikompilasi sebelumnya. Kode yang ditulis dengan cara ini tidak lagi diterima oleh pengkompilasi. Pengkompilasi sekarang mengeluarkan peringatan kompilator CC4599 untuk membantu mengidentifikasi argumen baris perintah include directory (-I) yang tidak cocok saat menggunakan file PCH.

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

    Contoh (sebelumnya)

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

    Contoh (setelah)

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

Perubahan Kesuaian Visual Studio 2013

Kompilator

  • Kata kunci akhir sekarang menghasilkan kesalahan simbol yang tidak terselesaikan di mana kata kunci tersebut akan dikompilasi sebelumnya:

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

    Dalam versi sebelumnya, kesalahan tidak dikeluarkan karena panggilan adalah virtual panggilan; namun, program akan mengalami crash saat runtime. Sekarang, kesalahan linker dikeluarkan karena kelas diketahui final. Dalam contoh ini, untuk memperbaiki kesalahan, Anda akan menautkan terhadap obj yang berisi definisi S2::f.

  • Ketika Anda menggunakan fungsi teman di namespace, Anda harus mendeklarasi ulang fungsi teman sebelum merujuknya atau Anda akan mendapatkan kesalahan karena kompilator sekarang sesuai dengan ISO C++ Standard. Misalnya, contoh ini tidak lagi mengkompilasi:

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

    Untuk memperbaiki kode ini, deklarasikan friend fungsi:

    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);
        }
    
  • Standar C++ tidak mengizinkan spesialisasi eksplisit di kelas. Meskipun pengkompilasi Microsoft C++ memungkinkannya dalam beberapa kasus, dalam kasus seperti contoh berikut, kesalahan sekarang dihasilkan karena pengkompilasi tidak menganggap fungsi kedua sebagai spesialisasi yang pertama.

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

    Untuk memperbaiki kode ini, ubah fungsi kedua:

    template <> void f(char& val);
    
  • Pengkompilasi tidak lagi mencoba memisahkan dua fungsi dalam contoh berikut, dan sekarang memancarkan kesalahan:

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

    Untuk memperbaiki kode ini, klarifikasi panggilan:

    template< typename T> void Func(T* t = nullptr);
    template< typename T> void Func(...);
    
    int main() {
        Func< int>(nullptr); // ok
    }
    
  • Sebelum pengkompilasi sesuai dengan ISO C++11, kode berikut akan dikompilasi dan menyebabkan x penyelesaian untuk mengetik int:

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

    Kode ini sekarang diselesaikan x ke jenis std::initializer_list<int> dan menyebabkan kesalahan pada baris berikutnya yang mencoba menetapkan x untuk mengetik int. (Tidak ada konversi secara default.) Untuk memperbaiki kode ini, gunakan int untuk mengganti auto:

    int x = {0};
    int y = x;
    
  • Inisialisasi agregat tidak lagi diizinkan ketika jenis nilai sebelah kanan tidak cocok dengan jenis nilai sebelah kiri yang sedang diinisialisasi, dan kesalahan dikeluarkan karena ISO C++11 Standard memerlukan inisialisasi seragam untuk bekerja tanpa mempersempit konversi. Sebelumnya, jika konversi yang dipersempit tersedia, peringatan Compiler Warning (level 4) C4242 akan dikeluarkan alih-alih kesalahan.

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

    Untuk memperbaiki kode ini, tambahkan konversi penyempitan eksplisit:

    int i = 0;
    char c = {static_cast<char>(i)};
    
  • Inisialisasi berikut tidak lagi diizinkan:

    void *p = {{0}};
    

    Untuk memperbaiki kode ini, gunakan salah satu formulir ini:

    void *p = 0;
    // or
    void *p = {0};
    
  • Pencarian nama telah berubah. Kode berikut diselesaikan secara berbeda di pengkompilasi C++ di Visual Studio 2012 dan Visual Studio 2013:

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

    Di Visual Studio 2012, E1 ekspresi E1::b dalam diselesaikan ::E1 dalam cakupan global. Di Visual Studio 2013, E1 dalam ekspresi E1::b diselesaikan ke typedef E2 definisi di main() dan memiliki jenis ::E2.

  • Tata letak objek telah berubah. Pada x64, tata letak objek kelas dapat berubah dari rilis sebelumnya. Jika memiliki virtual fungsi tetapi tidak memiliki kelas dasar yang memiliki virtual fungsi, model objek pengkompilasi menyisipkan penunjuk ke virtual tabel fungsi setelah tata letak anggota data. Ini berarti tata letak mungkin tidak optimal dalam semua kasus. Dalam rilis sebelumnya, pengoptimalan untuk x64 akan mencoba meningkatkan tata letak untuk Anda, tetapi karena gagal berfungsi dengan benar dalam situasi kode yang kompleks, pengoptimalan akan dihapus di Visual Studio 2013. Misalnya, pertimbangkan kode ini:

    __declspec(align(16)) struct S1 {
    };
    
    struct S2 {
        virtual ~S2();
        void *p;
        S1 s;
    };
    
  • Di Visual Studio 2013, hasil pada sizeof(S2) x64 adalah 48, tetapi dalam rilis sebelumnya, ini mengevaluasi ke 32. Untuk membuat ini mengevaluasi ke 32 di pengkompilasi Visual Studio 2013 C++ untuk x64, tambahkan kelas dasar dummy yang memiliki virtual fungsi:

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

    Untuk menemukan tempat dalam kode Anda yang akan dioptimalkan oleh rilis sebelumnya, gunakan kompilator dari rilis tersebut /W3 bersama dengan opsi kompilator dan aktifkan peringatan C4370. Misalnya:

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

    Sebelum Visual Studio 2013, kode ini menghasilkan pesan ini: "peringatan C4370: 'S2' : tata letak kelas telah berubah dari versi kompiler sebelumnya karena pengemasan yang lebih baik".

    Pengkompilasi x86 memiliki masalah tata letak suboptimal yang sama di semua versi pengkompilasi. Misalnya, jika kode ini dikompilasi untuk x86:

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

    Hasilnya sizeof(S) adalah 24. Namun, dapat dikurangi menjadi 16 jika Anda menggunakan solusi yang disebutkan untuk x64:

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

Pustaka Standar

Pengkompilasi C++ di Visual Studio 2013 mendeteksi ketidakcocokan dalam _ITERATOR_DEBUG_LEVEL, yang diterapkan di Visual Studio 2010, dan ketidakcocokan RuntimeLibrary. Ketidakcocokan ini terjadi ketika opsi /MT kompilator (rilis statis), /MTd (debug statis), /MD (rilis dinamis), dan /MDd (debug dinamis) dicampur.

  • Jika kode Anda mengakui templat alias simulasi rilis sebelumnya, Anda harus mengubahnya. Misalnya, alih-alih allocator_traits<A>::rebind_alloc<U>::other, sekarang Anda harus mengatakan allocator_traits<A>::rebind_alloc<U>. Meskipun ratio_add<R1, R2>::type tidak lagi diperlukan dan kami sekarang menyarankan Anda mengatakan ratio_add<R1, R2>, yang pertama akan tetap dikompilasi karena ratio<N, D> diperlukan untuk memiliki typedef "jenis" untuk rasio yang dikurangi, yang akan menjadi jenis yang sama jika sudah berkurang.

  • Anda harus menggunakan #include <algorithm> ketika Anda memanggil std::min() atau std::max().

  • Jika kode Anda yang ada menggunakan enum cakupan simulasi rilis sebelumnya—enum tradisional yang tidak tercakup yang dibungkus dalam namespace—Anda harus mengubahnya. Misalnya, jika Anda merujuk ke jenis std::future_status::future_status, sekarang Anda harus mengatakan std::future_status. Namun, sebagian besar kode tidak terpengaruh—misalnya, std::future_status::ready masih dikompilasi.

  • explicit operator bool() lebih ketat daripada operator unspecified-bool-type(). explicit operator bool() mengizinkan konversi eksplisit ke bool—misalnya, diberikan shared_ptr<X> sp, baik static_cast<bool>(sp) dan bool b(sp) valid—dan "konversi kontekstual" yang dapat diuji Boolean ke bool—misalnya, if (sp), !sp, sp && apa pun. Namun, explicit operator bool() melarang konversi implisit ke bool, sehingga Anda tidak dapat mengatakan bool b = sp; dan diberi jenis pengembalian bool, Anda tidak dapat mengatakan return sp.

  • Sekarang templat variadik nyata diimplementasikan, _VARIADIC_MAX dan makro terkait tidak berpengaruh. Jika Anda masih menentukan _VARIADIC_MAX, itu diabaikan. Jika Anda mengakui mesin makro kami yang dimaksudkan untuk mendukung templat variadik yang disimulasikan dengan cara lain, Anda harus mengubah kode Anda.

  • Selain kata kunci biasa, header Pustaka Standar C++ sekarang melarang penggantian makro kata kunci peka konteks dan akhir.

  • reference_wrapper, ref(), dan cref() sekarang melarang pengikatan ke objek sementara.

  • <random> sekarang secara ketat memberlakukan prasyarat waktu kompilasinya.

  • Berbagai sifat jenis Pustaka Standar C++ memiliki prasyarat "T akan menjadi jenis lengkap". Meskipun kompilator sekarang memberlakukan prasyarat ini lebih ketat, itu mungkin tidak memberlakukannya dalam semua situasi. (Karena pelanggaran prasyarat Pustaka Standar C++ memicu perilaku yang tidak ditentukan, Standar tidak menjamin penegakan.)

  • Pustaka Standar C++ tidak mendukung /clr:oldSyntax.

  • Spesifikasi C++11 untuk common_type<> memiliki konsekuensi yang tidak terduga dan tidak diinginkan; khususnya, itu membuat common_type<int, int>::type pengembalian int&&. Oleh karena itu, kompilator mengimplementasikan Resolusi yang Diusulkan untuk Masalah Grup Kerja Pustaka 2141, yang membuat common_type<int, int="">::type pengembalian int.

    Sebagai efek samping dari perubahan ini, kasus identitas tidak lagi berfungsi (common_type<T> tidak selalu menghasilkan jenis T). Perilaku ini sesuai dengan Resolusi yang Diusulkan, tetapi melanggar kode apa pun yang bergantung pada perilaku sebelumnya.

    Jika Anda memerlukan sifat jenis identitas, jangan gunakan non-standar std::identity yang ditentukan karena <type_traits> tidak akan berfungsi untuk <void>. Sebagai gantinya, terapkan sifat jenis identitas Anda sendiri agar sesuai dengan kebutuhan Anda. Berikut contohnya:

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

MFC dan ATL

  • Hanya Visual Studio 2013: Pustaka MFC MBCS tidak disertakan dalam Visual Studio karena Unicode sangat populer dan penggunaan MBCS telah menurun secara signifikan. Perubahan ini juga membuat MFC lebih selaras dengan Windows SDK itu sendiri, karena banyak kontrol dan pesan baru hanya Unicode. Namun, jika Anda harus terus menggunakan pustaka MFC MBCS, Anda dapat mengunduhnya dari Pusat Unduhan Microsoft di Pustaka MFC Multibyte untuk Visual Studio 2013. Paket Visual C++ Redistributable masih menyertakan pustaka ini. (Catatan: DLL MBCS disertakan dalam komponen penyiapan C++ di Visual Studio 2015 dan yang lebih baru).

  • Aksesibilitas untuk pita MFC diubah. Alih-alih arsitektur satu tingkat, sekarang ada arsitektur hierarkis. Anda masih dapat menggunakan perilaku lama dengan memanggil CRibbonBar::EnableSingleLevelAccessibilityMode().

  • CDatabase::GetConnect metode dihapus. Untuk meningkatkan keamanan, string koneksi sekarang disimpan dienkripsi dan didekripsi hanya sesuai kebutuhan; tidak dapat dikembalikan sebagai teks biasa. String dapat diperoleh dengan menggunakan CDatabase::Dump metode .

  • CWnd::OnPowerBroadcast Tanda tangan diubah. Tanda tangan handler pesan ini diubah untuk mengambil LPARAM sebagai parameter kedua.

  • Tanda tangan diubah untuk mengakomodasi penanganan pesan. Daftar parameter fungsi berikut telah diubah untuk menggunakan penangan pesan ON_WM_* yang baru ditambahkan:

    • CWnd::OnDisplayChange diubah ke (UINT, int, int) alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_DISPLAYCHANGE baru dapat digunakan di peta pesan.

    • CFrameWnd::OnDDEInitiate diubah ke (CWnd*, UINT, UNIT) alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_DDE_INITIATE baru dapat digunakan di peta pesan.

    • CFrameWnd::OnDDEExecute diubah ke (CWnd*, HANDLE) alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_DDE_EXECUTE baru dapat digunakan di peta pesan.

    • CFrameWnd::OnDDETerminate diubah menjadi (CWnd*) sebagai parameter alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_DDE_TERMINATE baru dapat digunakan di peta pesan.

    • CMFCMaskedEdit::OnCut diubah menjadi tidak ada parameter alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_CUT baru dapat digunakan di peta pesan.

    • CMFCMaskedEdit::OnClear diubah menjadi tidak ada parameter alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_CLEAR baru dapat digunakan dalam peta pesan.

    • CMFCMaskedEdit::OnPaste diubah menjadi tidak ada parameter alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_PASTE baru dapat digunakan di peta pesan.

  • #ifdef direktif dalam file header MFC dihapus. #ifdef Banyak arahan dalam file header MFC yang terkait dengan versi Windows yang tidak didukung (WINVER < 0x0501) dihapus.

  • ATL DLL (atl120.dll) dihapus. ATL sekarang disediakan sebagai header dan pustaka statis (atls.lib).

  • Atlsd.lib, atlsn.lib, dan atlsnd.lib dihapus. Atls.lib tidak lagi memiliki dependensi atau kode set karakter yang khusus untuk debug/rilis. Karena berfungsi sama untuk Unicode/ANSI dan debug/rilis, hanya satu versi pustaka yang diperlukan.

  • Alat ATL/MFC Trace dihapus bersama dengan ATL DLL, dan mekanisme pelacakan disederhanakan. CTraceCategory Konstruktor sekarang mengambil satu parameter (nama kategori), dan makro TRACE memanggil fungsi pelaporan debug CRT.

Perubahan Melanggar Visual Studio 2012

Kompilator

  • Opsi /Yl pengkompilasi telah berubah. Secara default, pengkompilasi menggunakan opsi ini, yang dapat menyebabkan kesalahan LNK2011 dalam kondisi tertentu. Untuk informasi selengkapnya, lihat /Yl (Menyuntikkan Referensi PCH untuk Pustaka Debug).

  • Dalam kode yang dikompilasi dengan menggunakan /clr, enum kata kunci kelas mendefinisikan enum C++11, bukan enum runtime bahasa umum (CLR). Untuk menentukan enum CLR, Anda harus eksplisit tentang aksesibilitasnya.

  • Gunakan kata kunci templat untuk secara eksplisit mendisambiguasi nama dependen (kesesuaian Standar Bahasa C++). Dalam contoh berikut, kata kunci templat yang disorot wajib untuk mengatasi ambiguitas. Untuk informasi selengkapnya, lihat Resolusi Nama untuk Jenis Dependen.

    template < typename X = "", typename = "" AY = "">
    struct Container { typedef typename AY::template Rebind< X> ::Other AX; };
    
  • Ekspresi konstan jenis float tidak lagi diizinkan sebagai argumen templat, seperti yang ditunjukkan dalam contoh berikut.

    template<float n=3.14>
    struct B {};  // error C2993: 'float': illegal type for non-type template parameter 'n'
    
  • Kode yang dikompilasi dengan menggunakan /GS opsi baris perintah dan yang memiliki kerentanan off-by-one dapat menyebabkan penghentian proses pada runtime, seperti yang ditunjukkan dalam contoh pseudocode berikut.

    char buf[MAX]; int cch; ManipulateString(buf, &cch); // ... buf[cch] = '\0'; // if cch >= MAX, process will terminate
    
  • Arsitektur default untuk build x86 diubah menjadi SSE2; oleh karena itu, kompilator dapat memancarkan instruksi SSE, dan akan menggunakan register XMM untuk melakukan perhitungan floating-point. Jika Anda ingin kembali ke perilaku sebelumnya, gunakan /arch:IA32 bendera pengkompilasi untuk menentukan arsitektur sebagai IA32.

  • Kompilator dapat mengeluarkan peringatan Compiler Warning (tingkat 4) C4703 dan C4701 di mana sebelumnya tidak. Pengkompilasi menerapkan pemeriksaan yang lebih kuat untuk penggunaan variabel lokal jenis pointer yang tidak diinisialisasi.

  • Ketika bendera /HIGHENTROPYVA linker baru ditentukan, Windows 8 biasanya menyebabkan alokasi memori mengembalikan alamat 64-bit. (Sebelum Windows 8, alokasi tersebut lebih sering mengembalikan alamat yang kurang dari 2 GB.) Perubahan ini dapat mengekspos bug pemotongan pointer dalam kode yang ada. Secara default, sakelar ini aktif. Untuk menonaktifkan perilaku ini, tentukan /HIGHENTROPYVA:NO.

  • Pengkompilasi terkelola (Visual Basic/C#) juga mendukung /HIGHENTROPYVA build terkelola. Namun, dalam hal ini, /HIGHENTROPYVAswitch nonaktif secara default.

IDE

  • Meskipun kami menyarankan agar Anda tidak membuat aplikasi Formulir Windows di C++/CLI, pemeliharaan aplikasi UI C++/CLI yang ada didukung. Jika Anda harus membuat aplikasi Formulir Windows, atau aplikasi UI .NET lainnya, gunakan C# atau Visual Basic. Gunakan C++/CLI hanya untuk tujuan interoperabilitas.

Pustaka Pola Paralel dan Pustaka Runtime Konkurensi

Enumerasi SchedulerTypeUmsThreadDefault tidak digunakan lagi. Spesifikasi UmsThreadDefault menghasilkan peringatan yang tidak digunakan lagi, dan secara internal memetakan kembali ke ThreadScheduler.

Pustaka Standar

  • Setelah perubahan mencolok antara standar C++98/03 dan C++11, menggunakan argumen templat eksplisit untuk dipanggil make_pair() — seperti dalam — biasanya tidak dikompilasi make_pair<int, int>(x, y) di Visual C++ di Visual Studio 2012. Solusinya adalah selalu memanggil make_pair() tanpa argumen templat eksplisit — seperti dalam make_pair(x, y). Menyediakan argumen templat eksplisit mengalahkan tujuan fungsi. Jika Anda memerlukan kontrol yang tepat atas jenis yang dihasilkan, gunakan pair alih-alih make_pair — seperti dalam pair<short, short>(int1, int2).

  • Perubahan melanggar lainnya antara standar C++98/03 dan C++11: Ketika A secara implisit dapat dikonversi ke B dan B secara implisit dapat dikonversi ke C, tetapi A tidak secara implisit dapat dikonversi ke C, C++98/03 dan Visual Studio 2010 diizinkan pair<A, X> untuk dikonversi (secara implisit atau eksplisit) ke pair<C, X>. (Jenis lain, X, tidak menarik di sini, dan tidak spesifik untuk jenis pertama dalam pasangan.) Pengkompilasi C++ di Visual Studio 2012 mendeteksi bahwa A tidak secara implisit dapat dikonversi ke C, dan menghapus konversi pasangan dari resolusi kelebihan beban. Perubahan ini positif untuk banyak skenario. Misalnya, kelebihan beban func(const pair<int, int>&) dan func(const pair<string, string>&), dan panggilan func() dengan pair<const char *, const char *> akan dikompilasi dengan perubahan ini. Namun, perubahan ini merusak kode yang bergantung pada konversi pasangan agresif. Kode tersebut biasanya dapat diperbaiki dengan melakukan satu bagian dari konversi secara eksplisit—misalnya, dengan meneruskan make_pair(static_cast<B>(a), x) ke fungsi yang mengharapkan pair<C, X>.

  • Templat variadik yang disimulasikan Visual Studio 2010—misalnya, make_shared<T>(arg1, arg2, argN)—hingga batas 10 argumen, dengan memberi stempel kelebihan beban dan spesialisasi dengan mesin pra-prosesor. Di Visual Studio 2012, batas ini dikurangi menjadi lima argumen untuk meningkatkan waktu kompilasi dan mengkompilasi konsumsi memori untuk sebagian besar pengguna. Namun, Anda dapat menetapkan batas sebelumnya dengan secara eksplisit menentukan _VARIADIC_MAX sebagai 10, di seluruh proyek.

  • C++11 17.6.4.3.1 [macro.names]/2 melarang penggantian makro kata kunci ketika header Pustaka Standar C++ disertakan. Header sekarang memancarkan kesalahan pengkompilasi jika mendeteksi kata kunci yang diganti makro. (Mendefinisikan _ALLOW_KEYWORD_MACROS memungkinkan kode tersebut untuk dikompilasi, tetapi kami sangat mencegah penggunaan tersebut.) Sebagai pengecualian, bentuk new makro diizinkan secara default, karena header secara komprehensif mempertahankan diri dengan menggunakan/#pragma push_macro("new")#undef new/#pragma pop_macro("new") . Menentukan _ENFORCE_BAN_OF_MACRO_NEW melakukan apa yang namanya tersirat.

  • Untuk menerapkan berbagai pengoptimalan dan pemeriksaan penelusuran kesalahan, implementasi Pustaka Standar C++ sengaja merusak kompatibilitas biner di antara versi Visual Studio (2005, 2008, 2010, 2012). Ketika Pustaka Standar C++ digunakan, pustaka ini melarang pencampuran file objek dan pustaka statis yang dikompilasi dengan menggunakan versi yang berbeda ke dalam satu biner (EXE atau DLL), dan melarang melewati objek Pustaka Standar C++ antara biner yang dikompilasi dengan menggunakan versi yang berbeda. Pencampuran file objek dan pustaka statis (menggunakan Pustaka Standar C++ yang dikompilasi dengan menggunakan Visual Studio 2010 dengan yang dikompilasi dengan menggunakan pengkompilasi C++ di Visual Studio 2012 memancarkan kesalahan linker tentang _MSC_VER ketidakcocokan, di mana _MSC_VER adalah makro yang berisi versi utama pengkompilasi (1700 untuk Visual C++ di Visual Studio 2012). Pemeriksaan ini tidak dapat mendeteksi pencampuran DLL, dan tidak dapat mendeteksi pencampuran yang melibatkan Visual Studio 2008 atau yang lebih lama.

  • Selain mendeteksi ketidakcocokan _ITERATOR_DEBUG_LEVEL, yang diterapkan di Visual Studio 2010, pengkompilasi C++ di Visual Studio 2012 mendeteksi ketidakcocokan Pustaka Runtime. Ketidakcocokan ini terjadi ketika opsi /MT pengkompilasi (rilis statis), /MTd (debug statis), /MD (rilis dinamis), dan /MDd (debug dinamis) dicampur.

  • operator<(), , operator>()operator<=(), dan operator>=() sebelumnya tersedia untuk std::unordered_map keluarga kontainer dan stdext::hash_map , meskipun implementasinya tidak berguna. Operator non-standar ini telah dihapus di Visual C++ di Visual Studio 2012. Selain itu, pelaksanaan operator==() dan operator!=() untuk std::unordered_map keluarga telah diperpanjang untuk mencakup stdext::hash_map keluarga. (Kami menyarankan agar Anda menghindari penggunaan stdext::hash_map keluarga dalam kode baru.)

  • C++11 22.4.1.4 [locale.codecvt] menentukan bahwa dan codecvt::do_length() harus mengambil parameter yang codecvt::length() dapat stateT& dimodifikasi, tetapi Visual Studio 2010 mengambil const stateT&. Pengkompilasi C++ di Visual Studio 2012 diambil stateT& sebagaimana diamanatkan oleh standar. Perbedaan ini signifikan bagi siapa saja yang mencoba mengambil alih fungsi do_length()virtual .

CRT

  • Timbunan C Runtime (CRT), yang digunakan untuk baru dan malloc(), tidak lagi privat. CRT sekarang menggunakan timbunan proses. Ini berarti bahwa tumpukan tidak dihancurkan ketika DLL dibongkar, sehingga DLL yang menautkan secara statis ke CRT harus memastikan memori yang dialokasikan oleh kode DLL dibersihkan sebelum dibongkar.

  • Fungsi ini iscsymf() menegaskan dengan nilai negatif.

  • Struktur threadlocaleinfostruct telah berubah untuk mengakomodasi perubahan pada fungsi lokal.

  • Fungsi CRT yang memiliki intrinsik yang sesuai seperti memxxx(), strxxx() dihapus dari intrin.h. Jika Anda menyertakan intrin.h hanya untuk fungsi-fungsi ini, Anda sekarang harus menyertakan header CRT yang sesuai.

MFC dan ATL

  • Dukungan Fusion yang dihapus (afxcomctl32.h); oleh karena itu, semua metode yang didefinisikan dalam <afxcomctl32.h> telah dihapus. File header <afxcomctl32.h> dan <afxcomctl32.inl> telah dihapus.

  • Mengubah nama menjadi CDockablePane::RemoveFromDefaultPaneDividierCDockablePane::RemoveFromDefaultPaneDivider.

  • Mengubah tanda tangan CFileDialog::SetDefExt untuk menggunakan LPCTSTR; oleh karena itu, build Unicode terpengaruh.

  • Menghapus kategori pelacakan ATL usang.

  • Mengubah tanda tangan CBasePane::MoveWindow untuk mengambil const CRect.

  • Mengubah tanda tangan CMFCEditBrowseCtrl::EnableBrowseButton.

  • Menghapus m_fntTabs dan m_fntTabsBold dari CMFCBaseTabCtrl.

  • Menambahkan parameter ke CMFCRibbonStatusBarPane konstruktor. (Ini adalah parameter default, sehingga tidak melanggar sumber.)

  • Menambahkan parameter ke CMFCRibbonCommandsListBox konstruktor. (Ini adalah parameter default, sehingga tidak melanggar sumber.)

  • AFXTrackMouse Menghapus API (dan proc timer terkait). Gunakan API Win32 TrackMouseEvent sebagai gantinya.

  • Menambahkan parameter ke CFolderPickerDialog konstruktor. (Ini adalah parameter default, sehingga tidak melanggar sumber.)

  • CFileStatus ukuran struktur berubah: Anggota m_attribute berubah dari BYTE ke DWORD (agar sesuai dengan nilai yang dikembalikan dari GetFileAttributes).

  • CRichEditCtrl dan CRichEditView gunakan MSFTEDIT_CLASS (kontrol RichEdit 4.1) alih-alih RICHEDIT_CLASS (kontrol RichEdit 3.0) dalam build Unicode.

  • Dihapus AFX_GLOBAL_DATA::IsWindowsThemingDrawParentBackground karena selalu TRUE pada Windows Vista, Windows 7, dan Windows 8.

  • Dihapus AFX_GLOBAL_DATA::IsWindowsLayerSupportAvailable karena selalu TRUE pada Windows Vista, Windows 7, dan Windows 8.

  • Dihapus AFX_GLOBAL_DATA::DwmExtendFrameIntoClientArea. Panggil Windows API langsung di Windows Vista, Windows 7, dan Windows 8.

  • Dihapus AFX_GLOBAL_DATA::DwmDefWindowProc. Panggil Windows API langsung di Windows Vista, Windows 7, dan Windows 8.

  • Diganti namanya AFX_GLOBAL_DATA::DwmIsCompositionEnabled menjadi IsDwmCompositionEnabled untuk menghilangkan tabrakan nama.

  • Mengubah pengidentifikasi untuk sejumlah timer internal MFC dan memindahkan definisi ke afxres.h (AFX_TIMER_ID_*).

  • Mengubah tanda tangan OnExitSizeMove metode untuk setuju dengan makro ON_WM_EXITSIZEMOVE:

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

  • Mengubah nama dan tanda tangan OnDWMCompositionChanged untuk setuju dengan makro ON_WM_DWMCOMPOSITIONCHANGED:

    • CFrameWndEx

    • CMDIFrameWndEx

    • CPaneFrameWnd

  • Mengubah tanda tangan OnMouseLeave metode untuk menyetujui makro ON_WM_MOUSELEAVE:

    • CMFCCaptionBar

    • CMFCColorBar

    • CMFCHeaderCtrl

    • CMFCProperySheetListBox

    • CMFCRibbonBar

    • CMFCRibbonPanelMenuBar

    • CMFCRibbonRichEditCtrl

    • CMFCSpinButtonCtrl

    • CMFCToolBar ReplaceThisText

    • CMFCToolBarComboBoxEdit

    • CMFCToolBarEditCtrl

    • CMFCAutoHideBar

  • Mengubah tanda tangan OnPowerBroadcast untuk setuju dengan makro ON_WM_POWERBROADCAST:

    • CFrameWndEx

    • CMDIFrameWndEx

  • Mengubah tanda tangan OnStyleChanged untuk setuju dengan makro ON_WM_STYLECHANGED:

    • CMFCListCtrl

    • CMFCStatusBar

  • Mengganti nama metode FontFamalyProcFonts internal menjadi FontFamilyProcFonts.

  • Menghapus banyak objek statis CString global untuk menghilangkan kebocoran memori dalam beberapa situasi (diganti dengan #defines), dan variabel anggota kelas berikut:

    • 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

  • Mengubah tanda tangan CKeyboardManager::ShowAllAccelerators dan menghapus parameter pemisah akselerator.

  • Ditambahkan CPropertyPage::GetParentSheet, dan di CPropertyPage kelas , panggil alih-alih GetParent untuk mendapatkan jendela lembar induk yang benar, yang mungkin merupakan jendela induk atau kakek-nenek ke CPropertyPage. Anda mungkin harus mengubah kode Anda untuk memanggil GetParentSheet alih-alih GetParent.

  • Memperbaiki peringatan #pragma yang tidak seimbang (push) di ATLBASE. H, yang menyebabkan peringatan dinonaktifkan dengan tidak benar. Peringatan tersebut sekarang diaktifkan dengan benar setelah ATLBASE. H telah diurai.

  • Memindahkan metode terkait D2D dari AFX_GLOBAL_DATA ke _AFX_D2D_STATE:

    • GetDirectD2dFactory

    • GetWriteFactory

    • GetWICFactory

    • InitD2D

    • ReleaseD2DRefs

    • IsD2DInitialized

    • D2D1MakeRotateMatrix

    • Alih-alih memanggil, misalnya, , afxGlobalData.IsD2DInitializedpanggil AfxGetD2DState->IsD2DInitialized.

  • MENGHAPUS ATL usang*. File CPP dari folder \atlmfc\include\.

  • afxGlobalData Memindahkan inisialisasi ke sesuai permintaan alih-alih pada waktu inisialisasi CRT, untuk memenuhi DLLMain persyaratan.

  • RemoveButtonByIndex Menambahkan metode ke CMFCOutlookBarPane kelas .

  • Dikoreksi CMFCCmdUsageCount::IsFreqeuntlyUsedCmd ke IsFrequentlyUsedCmd.

  • Mengoreksi beberapa instans ke RestoreOriginalstateRestoreOriginalState (CMFCToolBar, CMFCMenuBar, CMFCOutlookBarPane).

  • Menghapus metode yang tidak digunakan dari CDockablePane: , , IsDrawCaption, IsHideDisabledButtonsGetRecentSiblingPaneInfo, dan CanAdjustLayoutSetCaptionStyle.

  • CDockablePane Menghapus variabel m_bCaptionText anggota statis dan m_bHideDisabledButtons.

  • Menambahkan metode penimpaan DeleteString ke CMFCFontComboBox.

  • Menghapus metode yang tidak digunakan dari CPane: GetMinLength dan IsLastPaneOnLastRow.

  • Diganti namanya CPane::GetDockSiteRow(CDockingPanesRow *) menjadi CPane::SetDockSiteRow.

Perubahan Melanggar Visual Studio 2010

Kompilator

  • Kata auto kunci memiliki arti default baru. Karena penggunaan makna lama jarang terjadi, sebagian besar aplikasi tidak akan terpengaruh oleh perubahan ini.

  • Kata kunci baru static_assert diperkenalkan, yang akan menyebabkan konflik nama jika sudah ada pengidentifikasi dengan nama tersebut dalam kode Anda.

  • Dukungan untuk notasi lambda baru mengecualikan dukungan untuk pengkodean GUID yang tidak dikutip dalam atribut uuid IDL.

  • .NET Framework 4 memperkenalkan konsep pengecualian status yang rusak, yang merupakan pengecualian yang meninggalkan proses dalam keadaan rusak yang tidak dapat dipulihkan. Secara default, Anda tidak dapat menangkap pengecualian status yang rusak, bahkan dengan opsi pengkompilasi /EHa yang menangkap semua pengecualian lainnya. Untuk menangkap pengecualian status yang rusak secara eksplisit, gunakan pernyataan __except __try. Atau, terapkan atribut [HandledProcessCorruptedStateExceptions]untuk memungkinkan fungsi menangkap pengecualian status yang rusak. Perubahan ini terutama memengaruhi programmer sistem yang mungkin harus menangkap pengecualian status yang rusak. Delapan pengecualian tersebut adalah 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. Untuk informasi selengkapnya tentang pengecualian ini, lihat makro GetExceptionCode .

  • Opsi kompilator yang direvisi /GS melindungi dari overruns buffer secara lebih komprehensif daripada pada versi sebelumnya. Versi ini mungkin menyisipkan pemeriksaan keamanan tambahan di tumpukan yang mungkin mengurangi performa. Gunakan kata kunci baru __declspec(safebuffers) untuk menginstruksikan pengkompilasi untuk tidak menyisipkan pemeriksaan keamanan untuk fungsi tertentu.

  • Jika Anda mengkompilasi dengan /GL opsi /GL pengkompilasi (pengoptimalan Program Siapa le) dan /clr (Kompilasi Runtime Bahasa Umum), opsi diabaikan. Perubahan ini dilakukan karena kombinasi opsi pengkompilasi memberikan sedikit manfaat. Akibat perubahan ini, performa build ditingkatkan.

  • Secara default, dukungan untuk trigraf dinonaktifkan di Visual Studio 2010. /Zc:trigraphs Gunakan opsi pengkompilasi untuk mengaktifkan dukungan trigraf. Trigraf terdiri dari dua tanda tanya berturut-turut ("??") diikuti oleh karakter ketiga yang unik. Pengkompilasi menggantikan trigraf dengan karakter tanda baca yang sesuai. Misalnya, pengkompilasi menggantikan ??= trigraf dengan karakter '#'. Gunakan trigraf dalam file sumber C yang menggunakan kumpulan karakter yang tidak berisi representasi grafik yang nyaman untuk beberapa karakter tanda baca.

  • Linker tidak lagi mendukung pengoptimalan untuk Windows 98. Opsi /OPT (Pengoptimalan) menghasilkan kesalahan waktu kompilasi jika Anda menentukan /OPT:WIN98 atau /OPT:NOWIN98.

  • Opsi kompilator default yang ditentukan oleh properti sistem build RuntimeLibrary dan DebugInformationFormat telah diubah. Secara default, properti build ini ditentukan dalam proyek yang dibuat oleh Rilis Visual C++ 7.0 hingga 10.0. Jika Anda memigrasikan proyek yang dibuat oleh Visual C++ 6.0, pertimbangkan apakah akan menentukan nilai untuk properti ini.

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

CLR

  • Pengkompilasi Microsoft C# dan Visual Basic sekarang dapat menghasilkan perakitan interop utama (tanpa PIA). Rakitan no-PIA dapat menggunakan jenis COM tanpa penyebaran perakitan interop utama (PIA) yang relevan. Saat menggunakan rakitan no-PIA yang dihasilkan oleh Visual C# atau Visual Basic, Anda harus mereferensikan rakitan PIA pada perintah kompilasi sebelum Mereferensikan rakitan tanpa PIA yang menggunakan pustaka.

Proyek Visual Studio C++ dan MSBuild

  • Proyek Visual Studio C++ sekarang didasarkan pada alat MSBuild. Akibatnya, file proyek menggunakan format file XML baru dan akhiran file .vcxproj. Visual Studio 2010 secara otomatis mengonversi file proyek dari versi Visual Studio yang lebih lama ke format file baru. Proyek yang ada terpengaruh jika bergantung pada alat build sebelumnya, VCBUILD.exe, atau akhiran file proyek, .vcproj.

  • Dalam rilis sebelumnya, Visual C++ mendukung evaluasi lembar properti yang terlambat. Misalnya, lembar properti induk dapat mengimpor lembar properti anak, dan induk dapat menggunakan variabel yang ditentukan dalam anak untuk menentukan variabel lain. Evaluasi terlambat memungkinkan induk untuk menggunakan variabel anak bahkan sebelum lembar properti anak diimpor. Di Visual Studio 2010, variabel lembar proyek tidak dapat digunakan sebelum ditentukan karena MSBuild hanya mendukung evaluasi awal.

IDE

  • Kotak dialog penghentian aplikasi tidak lagi mengakhiri aplikasi. Dalam rilis sebelumnya, ketika abort() fungsi atau terminate() menutup build ritel aplikasi, Pustaka Run-Time C menampilkan pesan penghentian aplikasi di jendela konsol atau kotak dialog. Pesan tersebut mengatakan sebagian, "Aplikasi ini telah meminta Runtime untuk mengakhirinya dengan cara yang tidak biasa. Silakan hubungi tim dukungan aplikasi untuk informasi lebih lanjut." Pesan penghentian aplikasi berlebihan karena Windows kemudian menampilkan handler penghentian saat ini, yang biasanya merupakan kotak dialog Pelaporan Galat Windows (Dr. Watson) atau debugger Visual Studio. Mulai dari Visual Studio 2010, Pustaka Run-Time C tidak menampilkan pesan. Selain itu, runtime mencegah aplikasi berakhir sebelum debugger dimulai. Ini adalah perubahan yang melanggar hanya jika Anda bergantung pada perilaku sebelumnya dari pesan penghentian aplikasi.

  • Khusus untuk Visual Studio 2010, IntelliSense tidak berfungsi untuk kode atau atribut C++/CLI, Temukan Semua Referensi tidak berfungsi untuk variabel lokal, dan Model Kode tidak mengambil nama jenis dari rakitan yang diimpor atau mengatasi jenis ke nama yang sepenuhnya memenuhi syarat.

Pustaka

  • Kelas Brankas Int disertakan dalam Visual C++ dan tidak lagi dalam unduhan terpisah. Ini adalah perubahan yang melanggar hanya jika Anda telah mengembangkan kelas yang juga bernama "Brankas Int".

  • Model penyebaran pustaka tidak lagi menggunakan manifes untuk menemukan versi tertentu dari pustaka tautan dinamis. Sebagai gantinya, nama setiap pustaka tautan dinamis berisi nomor versinya, dan Anda menggunakan nama tersebut untuk menemukan pustaka.

  • Di versi Visual Studio sebelumnya, Anda dapat membangun kembali pustaka run time. Visual Studio 2010 tidak lagi mendukung pembuatan salinan file pustaka run time C Anda sendiri.

Pustaka Standar

  • Header <iterator> tidak lagi disertakan secara otomatis oleh banyak file header lainnya. Sebagai gantinya, sertakan header tersebut secara eksplisit jika Anda memerlukan dukungan untuk iterator mandiri yang ditentukan di header. Proyek yang ada terpengaruh jika bergantung pada alat build sebelumnya, VCBUILD.exe, atau akhiran file proyek, .vcproj.iterator.

  • <algorithm> Di header, checked_* fungsi dan unchecked_* dihapus. Dan di <iterator>> header, checked_iterator kelas dihapus, dan unchecked_array_iterator kelas telah ditambahkan.

  • CComPtr::CComPtr(int) Konstruktor dihapus. Konstruktor itu memungkinkan CComPtr objek dibangun dari makro NULL, tetapi tidak perlu dan diizinkan konstruksi nonsensik dari bilangan bulat bukan nol.

    masih CComPtr dapat dibangun dari NULL, yang didefinisikan sebagai 0, tetapi akan gagal jika dibangun dari bilangan bulat selain literal 0. Gunakan nullptr sebagai gantinya.

  • Fungsi anggota berikut ctype dihapus: ctype::_Do_narrow_s, , ctype::_Do_widen_sctype::_narrow_s, ctype::_widen_s. Jika aplikasi menggunakan salah satu fungsi anggota ini, Anda harus menggantinya dengan versi yang tidak aman yang sesuai: ctype::do_narrow, , ctype::do_widenctype::narrow, ctype::widen.

Pustaka CRT, MFC, dan ATL

  • Dukungan telah dihapus bagi pengguna untuk membangun pustaka CRT, MFC, dan ATL. Misalnya, tidak ada file NMAKE yang sesuai yang disediakan. Namun, pengguna masih memiliki akses ke kode sumber untuk pustaka ini. Dan dokumen yang menjelaskan opsi MSBuild yang digunakan Microsoft untuk membangun pustaka ini mungkin akan diposting di Blog Tim Visual C++.

  • Dukungan MFC untuk IA64 telah dihapus. Namun, dukungan untuk CRT dan ATL pada IA64 masih disediakan.

  • Ordinal tidak lagi digunakan kembali dalam file module-definition (.def) MFC. Perubahan ini berarti ordinal tidak akan berbeda antara versi minor, dan kompatibilitas biner untuk paket layanan dan rilis rekayasa perbaikan cepat akan ditingkatkan.

  • Fungsi virtual baru ditambahkan ke CDocTemplate kelas . Fungsi virtual baru ini adalah Kelas CDocTemplate. Versi sebelumnya memiliki OpenDocumentFile dua parameter. Versi baru memiliki tiga parameter. Untuk mendukung manajer hidupkan ulang, kelas apa pun yang berasal dari CDocTemplate harus mengimplementasikan versi yang memiliki tiga parameter. Parameter baru adalah bAddToMRU.

Makro dan Variabel Lingkungan

  • Variabel lingkungan __MSVCRT_HEAP_SELECT tidak lagi didukung. Variabel lingkungan ini dihapus dan tidak ada penggantian.

Referensi Perakitan Makro Microsoft

  • Beberapa direktif dihapus dari pengkompilasi Referensi Perakitan Makro Microsoft. Direktif yang dihapus adalah .186, , .286, .287.286P, .8086, .8087, dan .NO87.

Perubahan Yang Melanggar Visual Studio 2008

Kompilator

  • Platform Windows 95, Windows 98, Windows ME, dan Windows NT tidak lagi didukung. Sistem operasi ini telah dihapus dari daftar platform yang ditargetkan.

  • Pengkompilasi tidak lagi mendukung beberapa atribut yang terkait langsung dengan ATL Server. Atribut berikut tidak lagi didukung:

    • perf_counter

    • perf_object

    • Perfmon

    • request_handler

    • soap_handler

    • soap_header

    • soap_method

    • tag_name

Proyek Visual Studio C++

  • Saat meningkatkan proyek dari versi Visual Studio sebelumnya, Anda mungkin harus memodifikasi makro WINVER dan _WIN32_WINNT sehingga lebih besar dari atau sama dengan 0x0500.

  • Dimulai dengan Visual Studio 2008, wizard proyek baru tidak memiliki opsi untuk membuat proyek C++ SQL Server. Proyek SQL Server yang dibuat dengan menggunakan versi Visual Studio yang lebih lama masih akan dikompilasi dan berfungsi dengan benar.

  • File header Windows API Winable.h telah dihapus. Sertakan Winuser.h sebagai gantinya.

  • Pustaka Windows API Rpcndr.lib telah dihapus. Tautkan dengan rpcrt4.lib sebagai gantinya.

CRT

  • Dukungan untuk Windows 95, Windows 98, Windows Millennium Edition, dan Windows NT 4.0 telah dihapus.

  • Variabel global berikut telah dihapus:

    • _osplatform

    • _osver

    • _winmajor

    • _winminor

    • _winver

  • Fungsi berikut telah dihapus. Gunakan fungsi GetVersion Windows API atau GetVersionEx sebagai gantinya:

    • _get_osplatform

    • _get_osver

    • _get_winmajor

    • _get_winminor

    • _get_winver

  • Sintaks untuk Anotasi SAL telah berubah. Untuk informasi selengkapnya, lihat Anotasi SAL.

  • Filter IEEE sekarang mendukung set instruksi SSE 4.1. Untuk informasi selengkapnya, lihat _fpieee_flt_fpieee_flt.

  • Pustaka Run-Time C yang dikirim dengan Visual Studio tidak lagi bergantung pada dll sistem msvcrt.dll.

Pustaka Standar

  • Dukungan untuk Windows 95, Windows 98, Windows Millennium Edition, dan Windows NT 4.0 telah dihapus.

  • Saat mengkompilasi dalam mode debug dengan _HAS_ITERATOR_DEBUGGING ditentukan (digantikan oleh _ITERATOR_DEBUG_LEVEL setelah Visual Studio 2010), aplikasi sekarang akan menegaskan ketika iterator mencoba untuk meningkatkan atau menurunkan melewati batas kontainer yang mendasar.

  • Variabel anggota c dari Kelas tumpukan sekarang dinyatakan dilindungi. Sebelumnya, variabel anggota ini dinyatakan publik.

  • Perilaku money_get::do_get telah berubah. Sebelumnya, ketika menguraikan jumlah moneter dengan lebih banyak digit pecahan daripada yang dipanggil oleh frac_digits, do_get digunakan untuk mengonsumsi semuanya. Sekarang, do_get berhenti mengurai setelah mengkonsumsi sebagian besar frac_digits karakter.

ATL

  • ATL tidak dapat dibangun tanpa dependensi pada CRT. Di versi Visual Studio yang lebih lama, Anda dapat menggunakan #define ATL_MIN_CRT untuk membuat proyek ATL minimal bergantung pada CRT. Di Visual Studio 2008, semua proyek ATL minimal bergantung pada CRT terlepas dari apakah ATL_MIN_CRT ditentukan.

  • Basis kode ATL Server telah dirilis sebagai proyek sumber bersama di CodePlex dan tidak diinstal sebagai bagian dari Visual Studio. Kelas pengodean dan pendekodean data dari atlenc.h dan fungsi dan kelas utilitas dari atlutil.h dan atlpath.h telah disimpan dan sekarang menjadi bagian dari pustaka ATL. Beberapa file yang terkait dengan ATL Server tidak lagi menjadi bagian dari Visual Studio.

  • Beberapa fungsi tidak lagi disertakan dalam DLL. Mereka masih terletak di pustaka impor. Ini tidak akan memengaruhi kode yang menggunakan fungsi secara statis. Ini hanya akan memengaruhi kode yang menggunakan fungsi-fungsi ini secara dinamis.

  • Makro PROP_ENTRY dan PROP_ENTRY_EX tidak digunakan lagi dan diganti dengan makro PROP_ENTRY_TYPE dan PROP_ENTRY_TYPE_EX karena alasan keamanan.

Kelas Bersama ATL/MFC

  • ATL tidak dapat dibangun tanpa dependensi pada CRT. Di versi Visual Studio yang lebih lama, Anda dapat menggunakan #define ATL_MIN_CRT untuk membuat proyek ATL minimal bergantung pada CRT. Di Visual Studio 2008, semua proyek ATL minimal bergantung pada CRT terlepas dari apakah ATL_MIN_CRT ditentukan.

  • Basis kode ATL Server telah dirilis sebagai proyek sumber bersama di CodePlex dan tidak diinstal sebagai bagian dari Visual Studio. Kelas pengodean dan pendekodean data dari atlenc.h dan fungsi dan kelas utilitas dari atlutil.h dan atlpath.h telah disimpan dan sekarang menjadi bagian dari pustaka ATL. Beberapa file yang terkait dengan ATL Server tidak lagi menjadi bagian dari Visual Studio.

  • Beberapa fungsi tidak lagi disertakan dalam DLL. Mereka masih terletak di pustaka impor. Ini tidak akan memengaruhi kode yang menggunakan fungsi secara statis. Ini hanya akan memengaruhi kode yang menggunakan fungsi-fungsi ini secara dinamis.

MFC

  • CTime Kelas: Kelas CTime sekarang menerima tanggal mulai dari 1/1/1900 C.E. alih-alih 1/1/1970 C.E.

  • Urutan tab kontrol dalam dialog MFC: Urutan tab yang benar dari beberapa kontrol dalam dialog MFC terganggu jika kontrol MFC ActiveX disisipkan dalam urutan tab. Perubahan ini memperbaiki masalah tersebut.

    Misalnya, buat aplikasi dialog MFC yang memiliki kontrol ActiveX dan beberapa kontrol edit. Posisikan kontrol ActiveX di tengah urutan tab kontrol edit. Mulai aplikasi, klik kontrol edit yang urutan tabnya setelah kontrol ActiveX, lalu tab. Sebelum perubahan ini, fokus masuk ke kontrol edit mengikuti kontrol ActiveX alih-alih kontrol edit berikutnya dalam urutan tab.

  • CFileDialog Kelas: Templat kustom untuk CFileDialog kelas tidak dapat secara otomatis di-port ke Windows Vista. Mereka masih dapat digunakan, tetapi tidak akan memiliki fungsionalitas tambahan atau tampilan dialog gaya Windows Vista.

  • CWnd Kelas dan CFrameWnd Kelas: Metode CWnd::GetMenuBarInfo dihapus.

    Metode ini CFrameWnd::GetMenuBarInfo sekarang menjadi metode non-virtual. Untuk informasi selengkapnya, lihat Fungsi GetMenuBarInfo di Windows SDK.

  • Dukungan MFC ISAPI: MFC tidak lagi mendukung pembangunan aplikasi dengan Internet Server Application Programming Interface (ISAPI). Jika Anda ingin membangun aplikasi ISAPI, hubungi ekstensi ISAPI secara langsung.

  • API ANSI yang tidak digunakan lagi: Versi ANSI dari beberapa metode MFC tidak digunakan lagi. Gunakan versi Unicode dari metode tersebut di aplikasi Anda di masa mendatang. Untuk informasi selengkapnya, lihat Persyaratan Build untuk Kontrol Umum Windows Vista.

Perubahan Melanggar Visual Studio 2005

CRT

  • Banyak fungsi tidak digunakan lagi. Lihat Fungsi CRT yang tidak digunakan lagi.

  • Banyak fungsi sekarang memvalidasi parameternya, menghentikan eksekusi jika diberikan parameter yang tidak valid. Validasi ini dapat memutus kode yang melewati parameter yang tidak valid dan bergantung pada fungsi yang mengabaikannya atau hanya mengembalikan kode kesalahan. Lihat Validasi Parameter.

  • Nilai deskriptor file -2 sekarang digunakan untuk menunjukkan bahwa stdout dan stderr tidak tersedia untuk output, misalnya, dalam aplikasi Windows yang tidak memiliki jendela konsol. Nilai sebelumnya yang digunakan adalah -1. Untuk informasi selengkapnya, lihat _fileno.

  • Pustaka CRT berulir tunggal (libc.lib dan libcd.lib) telah dihapus. Gunakan pustaka CRT multi-utas. Bendera /ML pengkompilasi tidak lagi didukung. Versi non-penguncian dari beberapa fungsi telah ditambahkan dalam kasus di mana perbedaan performa antara kode multithreaded dan kode utas tunggal berpotensi signifikan.

  • Kelebihan pow, double pow(int, int), dihapus agar lebih sesuai dengan standar.

  • Penentu format %n tidak lagi didukung secara default dalam keluarga fungsi cetak karena secara inheren tidak aman. Jika %n ditemui, perilaku defaultnya adalah memanggil handler parameter yang tidak valid. Untuk mengaktifkan dukungan %n, gunakan _set_printf_count_output (juga lihat _get_printf_count_output).

  • sprintf sekarang mencetak tanda negatif dari nol yang ditandatangani.

  • swprintf telah diubah agar sesuai dengan Standar; sekarang memerlukan parameter ukuran. Bentuk swprintf tanpa parameter ukuran telah ditolak.

  • _set_security_error_handler telah dihapus. Hapus panggilan apa pun ke fungsi tersebut; handler default adalah cara yang jauh lebih aman untuk menangani kesalahan keamanan.

  • time_t sekarang adalah nilai 64-bit (kecuali _USE_32BIT_TIME_T ditentukan).

  • _spawn, _wspawn Functions sekarang tidak errno tersentuh pada keberhasilan, seperti yang ditentukan oleh Standar C.

  • RTC sekarang menggunakan karakter lebar secara default.

  • Fungsi dukungan kata kontrol floating-point tidak digunakan lagi untuk aplikasi yang dikompilasi dengan /CLR atau /CLR:PURE. Fungsi yang terpengaruh adalah _clear87, , _clearfp, _control87_controlfp, _fpreset, _status87, _statusfp. Anda dapat menonaktifkan peringatan penghentian dengan mendefinisikan _CRT_MANAGED_FP_NO_DEPRECATE, tetapi penggunaan fungsi-fungsi ini dalam kode terkelola tidak dapat diprediksi dan tidak didukung.

  • Beberapa fungsi sekarang mengembalikan penunjuk const. Perilaku lama dan non-const dapat dipulihkan dengan menentukan _CONST_RETURN. Fungsi yang terpengaruh adalah

    • memchr, wmemchr

    • strchr, wcschr, _mbschr, _mbschr_l

    • strpbrk, wcspbrk, _mbspbrk, _mbspbrk_l

    • strrchr, wcsrchr, _mbsrchr, _mbsrchr_l

    • strstr, wcsstr, _mbsstr, _mbsstr_l

  • Saat menautkan dengan Setargv.obj atau Wsetargv.obj, tidak mungkin lagi untuk menekan ekspansi karakter wildcard pada baris perintah dengan mengapitnya dalam tanda kutip ganda. Untuk informasi selengkapnya, lihat Memperluas Argumen Wildcard.

Pustaka Standar (2005)

  • Kelas pengecualian (terletak di <exception> header) telah dipindahkan ke std namespace layanan. Di versi sebelumnya, kelas ini berada di namespace layanan global. Untuk mengatasi kesalahan yang menunjukkan bahwa kelas pengecualian tidak dapat ditemukan, tambahkan pernyataan penggunaan berikut ke kode Anda: using namespace std;

  • Saat memanggil valarray::resize(), konten valarray akan hilang dan akan digantikan oleh nilai default. Metode resize() ini dimaksudkan untuk menginisialisasi ulang valarray daripada menumbuhkannya secara dinamis seperti vektor.

  • Debug Iterator: Aplikasi yang dibangun dengan versi debug pustaka C-Runtime dan yang menggunakan iterator mungkin mulai melihat pernyataan pada runtime. Untuk menonaktifkan pernyataan ini, Anda harus menentukan _HAS_ITERATOR_DEBUGGING (digantikan setelah _ITERATOR_DEBUG_LEVEL Visual Studio 2010) menjadi 0. Untuk informasi selengkapnya, lihat Debug Dukungan Iterator

Perubahan Pemecahan Visual C++ .NET 2003

Kompilator

  • Menutup tanda kurung sekarang diperlukan untuk arahan praprosesor yang ditentukan (C2004).

  • Spesialisasi eksplisit tidak lagi menemukan parameter templat dari templat utama (Compiler Error C2146).

  • Anggota yang dilindungi (n) hanya dapat diakses melalui fungsi anggota kelas (B) yang mewarisi dari kelas (A) di mana itu (n) adalah anggota (Compiler Error C2247).

  • Peningkatan pemeriksaan aksesibilitas di kompilator sekarang mendeteksi kelas dasar yang tidak dapat diakses (Compiler Error C2248).

  • Pengecualian tidak dapat ditangkap jika konstruktor destruktor dan/atau salinan tidak dapat diakses (C2316).

  • Argumen default pada pointer ke fungsi tidak lagi diizinkan (Compiler Error C2383).

  • Anggota data statis tidak dapat diinisialisasi melalui kelas turunan (Compiler Error C2477).

  • Inisialisasi typedef a tidak diizinkan oleh standar dan sekarang menghasilkan kesalahan kompilator (Compiler Error C2513).

  • bool sekarang merupakan jenis yang tepat (Compiler Error C2632).

  • UDC sekarang dapat menciptakan ambiguitas dengan operator yang kelebihan beban (C2666).

  • Ekspresi lainnya sekarang dianggap sebagai konstanta pointer null yang valid (Compiler Error C2668).

  • templat<> sekarang diperlukan di tempat-tempat di mana pengkompilasi sebelumnya akan menyiratkannya (Compiler Error C2768).

  • Spesialisasi eksplisit dari fungsi anggota di luar kelas tidak valid jika fungsi telah dikhususkan secara eksplisit melalui spesialisasi kelas templat (Compiler Error C2910).

  • Parameter templat non-jenis titik mengambang tidak lagi diizinkan (Compiler Error C2993).

  • Templat kelas tidak diizinkan sebagai argumen jenis templat (C3206).

  • Nama fungsi Teman tidak lagi diperkenalkan dalam berisi namespace (Compiler Error C3767).

  • Pengkompilasi tidak akan lagi menerima koma tambahan dalam makro (C4002).

  • Objek jenis POD yang dibangun dengan inisialisasi formulir () akan diinisialisasi secara default (C4345).

  • typename sekarang diperlukan jika nama dependen akan diperlakukan sebagai jenis (Compiler Warning (tingkat 1) C4346).

  • Fungsi yang salah dianggap sebagai spesialisasi templat tidak lagi dipertimbangkan demikian (C4347).

  • Anggota data statis tidak dapat diinisialisasi melalui kelas turunan (C4356).

  • Spesialisasi templat kelas perlu ditentukan sebelum digunakan dalam jenis pengembalian (Compiler Warning (level 3) C4686).

  • Pengkompilasi sekarang melaporkan kode yang tidak dapat dijangkau (C4702).

Baca juga

Yang Baru untuk Visual C++ di Visual Studio