Riwayat perubahan Microsoft C/C++ 2003 - 2015

Artikel ini menjelaskan semua perubahan signifikan dari Visual Studio 2015 hingga Visual Studio 2003, dan dalam artikel ini istilah "perilaku baru" atau "sekarang" merujuk ke Visual Studio 2015 dan versi setelahnya. 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 merusak, dan biasanya diperlukan oleh modifikasi dalam standar bahasa C++, signature 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 Melintasi Objek CRT Lintas 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 Kepatuhan Visual Studio 2015

Pustaka Runtime C (CRT)

Perubahan Umum

  • Binaries yang sudah 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 ke Abaikan Semua Pustaka Default menjadi Ya atau Anda menggunakan opsi /NODEFAULTLIB pada baris perintah, maka Anda harus memperbarui daftar pustaka Anda (dalam properti Dependensi Tambahan) untuk menyertakan pustaka baru yang telah diubah. Ganti pustaka CRT lama (libcmt.lib, libcmtd.lib, msvcrt.lib, msvcrtd.lib) dengan pustaka yang direfaktor 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 perlu 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.libversi vcruntime.dll, libvcruntimed.lib, dan versi vcruntimed.dll. Versi di Visual Studio 2015 dan Visual Studio 2017 adalah 140. Lihat Pustaka CRT - Fitur.

<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 data lconv untuk wilayah global, bukan wilayah utas.

    Jika Anda menggunakan lokalisasi 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)
    • float dan long double versi fungsi titik mengambang acos, acosh, asin, asinh, atan, atanh, atan2, cbrt, ceil, copysign, cos, cosh, erf, erfc, exp, exp2, expm1, fabs, fdim, floor, fma, fmax, fmin, fmod, frexp, hypot, ilogb, ldexp, lgamma, llrint, llround, log, log10, log1p, log2, lrint, lround, modf, nearbyint, nextafter, nexttoward, remainder, remquo, rint, round, scalbln, scalbn, sin, sinh, sqrt, tan, tanh, tgamma, dan trunc

    Jika Anda memiliki kode yang menggunakan abs dengan jenis bilangan titik mengambang yang hanya menyertakan header <math.h>, versi bilangan titik mengambang tidak akan tersedia lagi. Panggilan sekarang dialihkan ke abs(int), bahkan ketika menggunakan 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 ketaatan terhadap spesifikasi IEEE-754 dan C11 Annex F sehubungan dengan input kasus khusus seperti NaN dan infinitas. 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 kini bersifat dinamis dan secara akurat mencerminkan mode pembulatan yang sedang digunakan.

<new> dan <new.h>

  • new dan delete

    Dalam versi pustaka sebelumnya, fungsi operator 'new' dan 'delete' yang didefinisikan implementasi diekspor dari DLL pustaka runtime (contohnya, msvcr120.dll). Fungsi operator ini sekarang selalu ditautkan secara statis ke dalam biner Anda, bahkan saat menggunakan pustaka runtime DLL.

    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 sepenuhnya 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 printf dan scanf sekarang didefinisikan secara inline.

    Definisi semua fungsi printf dan scanf telah dipindahkan sebaris ke dalam <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 Linker Input untuk menambahkan legacy_stdio_definitions.lib ke daftar yang dipisahkan titik koma.

    Ketika proyek Anda ditautkan dengan pustaka statis yang dikompilasi dengan rilis Visual Studio sebelum 2015, linker mungkin melaporkan simbol eksternal yang tak terpecahkan. 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
    
  • gets 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 gets tetapi untuk string bertipe lebar. Sebagai alternatif untuk fungsi-fungsi ini, pertimbangkan penggunaan fgets, fgetws, 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 tidak terdefinisi: 1.#IND

    Salah satu format ini mungkin telah diawali oleh tanda dan mungkin telah diformat sedikit berbeda tergantung pada lebar kolom dan ketelitian (kadang-kadang dengan efek yang tidak biasa, misalnya printf("%.2f\n", INFINITY) akan mencetak 1.#J karena #INF akan "dibulatkan" ke ketelitian 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 Tentu: nan(ind)

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

    Fungsi scanf telah dimodifikasi untuk mengurai string baru ini, sehingga string ini sekarang dapat dikirim dan diterima kembali melalui printf dan scanf.

  • Pemformatan dan penguraian floating point

    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 mengikuti mode pembulatan (yang dapat dikontrol melalui fesetround). Ini berpotensi menjadi perubahan yang mengganggu fungsi karena fungsi-fungsi ini bisa menghasilkan output berbeda. Hasil baru selalu lebih benar daripada hasil lama.

  • Penguraian titik float heksadesimal dan tak terbatas/NaN

    Algoritma penguraian floating point sekarang akan mengurai string floating point heksadesimal (seperti yang dihasilkan oleh spesifikasi format printf %a dan %A) serta semua string Infinity dan NaN yang dihasilkan oleh fungsi printf, seperti yang dijelaskan di atas.

  • %A dan %a pengisian nol

    Penentu format %a dan %A memformat angka titik mengambang sebagai mantissa heksadesimal dan eksponen biner. Dalam versi sebelumnya, fungsi printf akan salah menambahkan nol di awal string. 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 untuk penentu format %A dan %a adalah 6 pada versi pustaka yang 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

    Pengidentifikasi spesifikasi format/konversi %F 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 berasal dari era ruang alamat tersegmentasi: pengubah panjang ini digunakan untuk menunjukkan penunjuk jauh dan dekat, seperti pada %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 bentuk ini dalam beberapa keadaan. 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 format string

    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 kini terdeteksi dan dianggap sebagai parameter yang tidak valid.

  • modus _O_U8TEXT

    Fungsi _setmode sekarang melaporkan dengan benar mode untuk stream yang dibuka dalam mode in_O_U8TEXT. Di versi pustaka sebelumnya, pustaka akan melaporkan stream tersebut sebagai dibuka di _O_WTEXT.

    Ini adalah perubahan mendasar jika kode Anda menginterpretasikan mode _O_WTEXT untuk stream 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. Perpustakaan telah diubah untuk menyembunyikan detail implementasi. Sebagai bagian dari perubahan ini, FILE seperti yang didefinisikan dalam <stdio.h> sekarang adalah tipe opak 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 mengatur 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 mengakibatkan perubahan yang mempengaruhi waktu proses.

  • Fungsi alokasi yang diselaraskan

    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 pangkat dua, yang tidak berlaku untuk nol. Penyelarasan 0 yang diminta sekarang diperlakukan sebagai parameter yang tidak valid. Masalah ini telah diperbaiki, dan merupakan perubahan yang mempengaruhi kompatibilitas runtime.

  • Fungsi timbunan

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

  • tumpukan kecil

    Opsi smallheap tautan telah dihapus. Lihat Opsi Tautan.

  • _stat

    Fungsi keluarga _stat menggunakan CreateFile di Visual Studio 2015, alih-alih FindFirstFile seperti di Visual Studio 2013 dan sebelumnya. Ini berarti bahwa pada jalur yang diakhiri dengan garis miring berhasil jika jalur tersebut mengacu pada direktori, berbeda dengan sebelumnya ketika fungsi akan mengalami kesalahan dengan errno diatur ke ENOENT.

<string.h>

  • wcstok

    Intisari dari fungsi wcstok telah diubah untuk memenuhi persyaratan dari Standar C. Di versi pustaka sebelumnya, tanda tangan fungsi ini adalah:

    wchar_t* wcstok(wchar_t*, wchar_t const*)
    

    Ini menggunakan konteks internal setiap 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 mengompilasi kode C++, terdapat juga 'overload' inline dari wcstok yang memiliki 'signature' 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 diimplementasikan ulang menggunakan QueryPerformanceCounter dan sekarang bersifat monotonik.

  • 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 fungsi fstat dan _utime telah diperbaiki, sehingga semua fungsi ini sekarang menangani waktu musim panas dengan benar dan konsisten.

  • asktime

    Dalam versi sebelumnya, fungsi asctime akan mengisi hari dengan satu digit dengan nol di depannya, misalnya: Fri Jun 06 08:00:00 2014. Spesifikasi mengharuskan hari tersebut disertakan dengan spasi di 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, pengformatan waktu dengan spesifikasi format %c salah menggunakan representasi MM/DD/YY HH:MM:SS. Masalah ini telah diperbaiki.

  • timespec dan TIME_UTC

    Header <time.h> sekarang menentukan tipe timespec dan fungsi timespec_get dari Standar C11. Selain itu, makro TIME_UTC, untuk digunakan dengan fungsi timespec_get, sekarang didefinisikan. Pembaruan ini adalah perubahan signifikan 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 optimasi dan pemeriksaan debug baru, implementasi Pustaka Standar C++ di Visual Studio sengaja merusak kompatibilitas biner antara versi. 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 menghasilkan kesalahan linker mengenai 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.

  • pengalokasi 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 konstanta:

    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::deallocate

    Di Visual Studio 2013 dan versi sebelumnya, std::allocator::deallocate(p, n) mengabaikan argumen yang diteruskan untuk n. Standar C++ selalu mengharuskan bahwa n harus sama dengan nilai yang telah diteruskan sebagai argumen pertama dalam 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 menurut standar mungkin mengalami kerusakan saat waktu jalan.

  • 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
    tambahkan referensi tambah_referensi_lvalue
    memiliki_konstruktor_default dapat_dikonstruksi_default
    memiliki_konstruktor_salinan dapat_dibuat_melalui_penyalinan
    memiliki_konstruktor_pemindahan bisa_dikonstruksi_dengan_pemindahan
    memiliki konstruktor tanpa lemparan dapat_dibangun_kembali_secara_default_tanpa_lemparan
    memiliki_konstruktor_default_tanpa_throw dapat_dibangun_kembali_secara_default_tanpa_lemparan
    has_nothrow_copy is_nothrow_copy_constructible (apakah dapat dikonstruksi tanpa pengecualian)
    mempunyai_konstruktor_salinan_tanpa_lemparan is_nothrow_copy_constructible (apakah dapat dikonstruksi tanpa pengecualian)
    Mempunyai_konstruktor_pindah_tanpa_lemparan is_nothrow_move_constructible
    memiliki_penugasan_tanpa_lemparan is_nothrow_copy_assignable
    memiliki_penugasan_salinan_tanpa_pengecualian is_nothrow_copy_assignable
    has_nothrow_move_assign is_nothrow_move_assignable
    memiliki_konstruktor_sepele dapat_dikonstruksi_dengan_caraterbiasa_bawaan
    memiliki_konstruktor_default_Sepele dapat_dikonstruksi_dengan_caraterbiasa_bawaan
    memiliki_salinan_sepele bersifat_konstruktif_salinan_trivial
    has_trivial_move_constructor (memiliki konstruktor pemindahan sederhana) adalah_konstruksi_pindah_secara_trivial
    memiliki_penugasan_sepele is_trivially_copy_assignable (dapat ditetapkan salin secara sepele)
    memiliki_pengalihan_sepele dapat_dipindahkan_trivial_ditugaskan
    memiliki_destruktor_sepele dapat_dihancurkan_dengan_mudah
  • launch::any dan launch::sync kebijakan

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

MFC dan ATL

  • Kelas Microsoft Foundation (MFC)

    tidak lagi disertakan dalam penginstalan Standar Visual Studio karena ukuran 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 pengaturan Visual Studio dari Panel Kontrol di Program dan Fitur, atau dari media penginstalan.

    Paket Visual C++ Redistributable masih menyertakan pustaka ini.

Runtime Konkurensi

  • Makro Yield dari Windows.h berbenturan dengan concurrency::Context::Yield

    Runtime Konkruensi sebelumnya menggunakan #undef untuk membatalkan definisi makro Yield guna menghindari konflik antara makro Yield yang ditentukan dalam Windows.h h dan fungsi concurrency::Context::Yield. Ini #undef telah dihapus dan panggilan API setara baru yang tidak bertentangan concurrency::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 sederhana. 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 memutus lebih parah, dan dapat memengaruhi kompatibilitas biner, tetapi pemutusan kompatibilitas biner seperti 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 opsi /Za, karena tanpa /Za, penggunaan variabel perulangan setelah loop selesai 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 VSTest.Console.exe baris perintah.

  • 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. Biasanya pengguna dan penulis pustaka mendefinisikan char16_t dan char32_t sebagai alias dari uint16_t dan uint32_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 deklarasi typedef dan ganti nama pengidentifikasi lain yang bertabrakan dengan nama-nama ini.

  • Parameter templat non-jenis

    Kode tertentu yang melibatkan parameter templat non-tipe sekarang diperiksa untuk kompatibilitas tipe dengan benar 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>();
    }
    

    Kompilator saat ini memberikan kesalahan dengan tepat, karena jenis parameter templat tidak sesuai dengan argumen templat (parameter adalah pointer ke anggota yang bersifat const, tetapi fungsi f bersifat 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) pada 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 penyalin bersifat privat, sehingga objek tidak dapat disalin seperti yang biasanya dilakukan dalam penanganan 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)
    {
    }
    
  • Literal string 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 literal yang didefinisikan pengguna, tetapi karena tidak ada literal yang sesuai yang didefinisikan pengguna _x, pengkompilasi menghasilkan 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 yang digabungkan tunggal dalam rilis Visual 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 Pembebasan Memori dengan Ukuran C++. Perubahan menambahkan bentuk operator global delete yang mengambil parameter ukuran. Perubahan yang memutus adalah jika sebelumnya Anda menggunakan operator delete dengan tanda tangan yang sama (untuk menyesuaikan dengan operator placement new), Anda akan menerima kesalahan kompilator (C2956, yang terjadi pada titik di mana placement new digunakan, karena itulah posisi dalam kode di mana pengkompilasi mencoba mengidentifikasi operator delete yang sesuai).

    Fungsi void operator delete(void *, size_t) adalah operator placement delete yang sesuai dengan fungsi placement newvoid * operator new(size_t, size_t) di C++11. Dengan ukuran dealokasi C++14, fungsi penghapusan ini sekarang merupakan fungsi dealokasi pada umumnya (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 placement new dan placement delete:

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

    Masalah terjadi karena kecocokan tanda tangan fungsi antara operator "placement delete" yang telah Anda tentukan, dan operator berskala global yang baru. Pertimbangkan apakah Anda dapat menggunakan jenis yang berbeda selain size_t untuk "placement new" dan delete operator. Tipe dari size_ttypedef bergantung pada compiler; ini adalah typedef untuk unsigned int dalam MSVC. Solusi yang baik adalah menggunakan jenis enumerasi seperti ini:

    enum class my_type : size_t {};
    

    Kemudian, ubah definisi placement new dan delete untuk menggunakan jenis ini sebagai argumen kedua alih-alih size_t. Anda juga harus memperbarui panggilan ke placement new untuk meneruskan jenis baru (misalnya, dengan menggunakan static_cast<my_type> untuk mengonversi dari nilai bilangan bulat) dan memperbarui definisi new dan delete untuk mengonversi kembali ke jenis bilangan bulat. Anda tidak perlu menggunakan enum untuk ini; sebuah kelas dengan anggota size_t 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 hapus dengan dua argumen tidak ada dan tidak akan menyebabkan konflik dengan operator penempatan hapus Anda.

  • Anggota data union

    Anggota data dari union tidak dapat lagi memiliki tipe 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, hal ini juga dapat mengubah ukuran union.

  • Serikat anonim sekarang lebih sesuai dengan standar. Versi kompilator sebelumnya menghasilkan konstruktor dan destruktor eksplisit untuk union 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 dalam fungsi baru, dan tambahkan panggilan ke fungsi-fungsi ini dari konstruktor dan destruktor untuk union.

    #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 saat pemanggilan pertama is_base_of, kelas D belum didefinisikan.

    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.

  • Konstruktor penyalin

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

  • Fungsi main yang dideklarasikan sebagai ekstern "C" sekarang memerlukan tipe 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 diizinkan dalam inisialisasi 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 diterapkan untuk deklarasi ke depan. (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 maju 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 lainnya di dalam namespace Microsoft::WRL.

  • Perbaiki alamat yang salah dari

    Kode berikut sekarang menghasilkan C2440: '=': tidak dapat mengonversi dari 'type *' ke 'type'. Untuk memperbaiki kesalahan, ubah &(type) 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 larik konstan

    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 = &"";
    }
    
  • UDL string C++11

    1. Kode berikut sekarang menghasilkan kesalahan C3688: akhiran literal 'L' yang tidak valid; operator literal atau template operator literal '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 UDL diproses sebagai 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';
    }
    
  • Eksepsi MFC tidak dapat ditangkap melalui nilai karena tidak dapat disalin

    Kode berikut dalam aplikasi MFC sekarang menyebabkan kesalahan C2316: 'D': tidak dapat ditangkap karena destruktor dan/atau konstruktor 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;}
    
  • Tipe bergerak 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 tangkapan.

  • 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 dapat diubah menjadi penunjuk fungsi.

  • Lambdas dengan operator penyisipan 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, pindahkan definisi S2 ke posisi lebih atas.

    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: tipe 'int' tidak terduga

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

    Untuk memperbaiki masalah, tentukan A seperti ini:

    #define A int
    
  • Kurung tambahan dalam deklarasi

    Kode berikut menghasilkan kesalahan C2062: tipe 'int' tidak diharapkan

    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 yang dihasilkan kompilator dan __declspec(novtable)

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

  • auto memerlukan ekspresi tunggal dalam direct-list-initialization

    Kode berikut sekarang menghasilkan kesalahan C3518: 'testPositions': dalam konteks inisialisasi-daftar langsung, tipe data 'auto' hanya dapat disimpulkan dari satu ekspresi penginisialisasi.

    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 tipe vs. pointer ke tipe 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 perpustakaan. 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 sebelumnya dari kompilator memungkinkan non-anggota operator new dan non-anggota operator delete untuk dinyatakan sebagai statis, dan dideklarasikan dalam namespace selain namespace global. Perilaku lama ini menciptakan risiko bahwa program tidak akan memanggil operator atau implementasi new dan delete yang diinginkan oleh programmer, yang dapat menghasilkan masalah runtime yang tidak terlihat. 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 kompilator tidak memberikan pesan diagnostik tertentu, operator sebaris new dianggap salah bentuk.

  • Memanggil 'operator type()' (konversi yang ditentukan pengguna) pada tipe 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 spesifikasi jenis yang dijabarkan

    Versi kompilator sebelumnya mengizinkan typename dalam spesifikasi tipe yang terelaborasi, tetapi kode yang ditulis dengan cara ini salah secara semantik. 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;
    
  • Penentuan tipe 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 peringatan tersebut yang sekarang dikeluarkan pada baris yang berbeda dibandingkan sebelumnya, peringatan yang sebelumnya dihilangkan dengan menggunakan #pragma warning(disable:####) mungkin tidak lagi dihilangkan seperti yang dimaksudkan. Untuk menekan peringatan ini seperti yang dimaksudkan, mungkin perlu untuk memindahkan #pragma warning(disable:####) direktif ke baris di atas kasus pertama yang menyebabkan peringatan. 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 spesifikator direktori utama '..' 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 diagnosa tertentu, kami juga menyarankan agar spesifikator direktori induk ".." tidak boleh digunakan untuk menentukan direktori penyertaan untuk proyek Anda.

  • #pragma optimize() melebihi akhir dari file header (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 flag optimasi yang diberikan pada pengompilasi melalui baris perintah.

    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"
    
  • Ketidaksesuaian #pragma warning(push) dan #pragma warning(pop) (hanya memengaruhi /Wall/WX)

    Versi kompilator sebelumnya tidak mendeteksi #pragma warning(push) perubahan status yang dipasangkan dengan #pragma warning(pop) perubahan status di file sumber yang berbeda, yang jarang diinginkan. Perilaku lama ini menciptakan risiko bahwa program akan dikompilasi dengan serangkaian peringatan yang berbeda dari yang dimaksudkan oleh programmer, yang mungkin mengakibatkan terjadinya perilaku runtime yang buruk secara diam-diam. 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 yang 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 karena peningkatan pelacakan status peringatan pragma

    Versi sebelumnya dari kompilator melacak perubahan status peringatan pragma dengan kurang efektif sehingga tidak semua peringatan yang dimaksud dapat dikeluarkan. Perilaku ini menimbulkan risiko bahwa peringatan tertentu akan secara efektif ditekan dalam keadaan yang berbeda dari yang diinginkan oleh programmer. Kompilator sekarang melacak #pragma warning status dengan lebih kuat -- terutama terkait dengan perubahan #pragma warning 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++ mengalami perubahan dan peningkatan dalam kemampuan untuk memanggil fungsi secara sebaris dibandingkan dengan versi kompilator sebelumnya, yang mungkin memungkinkan pengkompilasi untuk membuktikan bahwa kode tertentu sekarang tidak dapat diakses. 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 peringatan baru 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 spesifikasi decltype karena tidak adanya 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 ekspresi decltype yang tidak memiliki penggunaan kata kunci typename yang diperlukan untuk menetapkan bahwa nama dependen adalah tipe, kompilator mengeluarkan peringatan C4346 bersamaan dengan kesalahan 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 bergantung bukan tipe (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> ()));
    };
    
  • volatile variabel 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 pengualifikasi 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 ke depan enum tidak diizinkan dalam kode WinRT (hanya mempengaruhi /ZW)

    Kode yang dikompilasi untuk Windows Runtime (WinRT) tidak memungkinkan jenis enum untuk dideklarasikan terlebih dahulu, mirip dengan ketika kode C++ terkelola dikompilasi untuk .Net Framework menggunakan opsi pengompilasi /clr. 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 terstruktur dengan baik (tanpa membutuhkan diagnostik) dan dapat menyebabkan masalah memori yang diakibatkan oleh operator new dan delete yang tidak cocok (terutama ketika digunakan bersama dengan dealokasi dengan ukuran) yang sulit untuk 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_convertible sekarang mendeteksi penugasan diri sendiri (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 dikonfigurasi dengan benar menjadi false saat diterapkan ke tipe kelas dengan konstruktor salinan privat atau yang dihapus.

    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 asersi statis gagal.

  • Konstruktor salinan trivial atau pindah yang diatur ulang atau dihapus menghormati penentu akses

    Versi kompilator sebelumnya tidak memeriksa penentu akses dari konstruktor salinan dan pemindahan sepele yang di-default-kan atau dihapus sebelum mengizinkan pemanggilan mereka. 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. Pengompilasi sekarang memeriksa penentu akses dari konstruktor penyalinan sepele yang dijadikan default atau dihapus dan konstruktor pemindahan untuk menentukan apakah 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 untuk kode ATL yang diatribusikan (Tingkat 1 (/W1) secara default diaktifkan)

    Versi sebelumnya dari kompilator mendukung kode ATL yang memiliki atribut. Sebagai langkah berikutnya dalam menghapus dukungan untuk kode ATL atribut yang dimulai di Visual Studio 2008, kode ATL atribut tersebut telah dihentikan. 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"
    
  • Header yang telah dikompilasi sebelumnya (PCH) dan direktori pencantuman yang tidak cocok (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 Kesesuaian Standar Visual Studio 2013

Kompilator

  • Kata kunci final sekarang menghasilkan kesalahan simbol yang tidak terselesaikan, padahal sebelumnya dapat dikompilasi.

    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 itu adalah panggilan virtual; namun, program akan mengalami kerusakan saat waktu jalan. Sekarang, sebuah error linker terjadi 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 kompilator sesuai dengan ISO C++11, kode berikut akan dikompilasi dan menyebabkan x untuk menyelesaikan sebagai tipe int.

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

    Kode ini sekarang menyelesaikan x menjadi tipe std::initializer_list<int> dan menyebabkan kesalahan pada baris berikutnya yang mencoba menetapkan x ke tipe 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;
    }
    

    Dalam Visual Studio 2012, ekspresi E1 di E1::b diselesaikan menjadi ::E1 dalam cakupan global. Di Visual Studio 2013, E1 dalam ekspresi E1::b mengacu pada definisi typedef E2 di main() dan bertipe ::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 kompiler akan 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 simbol sizeof(S2) pada x64 adalah 48, tetapi dalam rilis sebelumnya, hasilnya dihasilkan menjadi 32. Untuk membuat ini mengevaluasi ke 32 di pengkompilasi Visual Studio 2013 C++ pada x64, tambahkan kelas dasar dummy yang memiliki sebuah fungsi virtual.

    __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 bersama dengan opsi kompilator /W3 dan aktifkan peringatan C4370. Contohnya:

    #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 dari kata kunci yang peka terhadap konteks seperti override dan final.

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

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

  • Berbagai sifat tipe dari Pustaka Standar C++ memiliki prasyarat "T harus merupakan tipe yang 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, ini membuat common_type<int, int>::type mengembalikan int&&. Oleh karena itu, kompilator mengimplementasikan Resolusi Usulan untuk Masalah Kelompok Kerja Perpustakaan 2141, yang membuat common_type<int, int="">::type mengembalikan 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 identitas jenis, jangan gunakan std::identity yang tidak standar dan ditentukan dalam <type_traits> karena 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 .

  • Tanda tangan dari CWnd::OnPowerBroadcast telah 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, bukan (WPARAM, LPARAM), sehingga makro ON_WM_DDE_TERMINATE yang baru dapat digunakan dalam peta pesan.

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

    • CMFCMaskedEdit::OnClear diubah menjadi tanpa parameter daripada (WPARAM, LPARAM) sehingga makro ON_WM_CLEAR baru dapat digunakan dalam peta pesan.

    • CMFCMaskedEdit::OnPaste diubah menjadi tanpa parameter alih-alih (WPARAM, LPARAM) sehingga makro ON_WM_PASTE yang baru dapat digunakan di message map.

  • #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 Signifikan 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 lebih lanjut, lihat /Yl (Suntikkan Referensi PCH untuk Perpustakaan 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 Tipe yang Bergantung.

    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 parameter linker baru /HIGHENTROPYVA ditentukan, Windows 8 biasanya membuat 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 Kesamaan

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

Pustaka Standar

  • Setelah perubahan signifikan antara standar C++98/03 dan C++11, penggunaan argumen templat secara eksplisit untuk memanggil make_pair() — seperti dalam make_pair<int, int>(x, y) — biasanya tidak dapat dikompilasi di Visual C++ pada 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 mendasar lainnya antara standar C++98/03 dan C++11: Ketika A dapat dikonversi secara implisit ke B dan B dapat dikonversi secara implisit ke C, tetapi A tidak dapat dikonversi secara implisit ke C, C++98/03 dan Visual Studio 2010 mengizinkan pair<A, X> 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 mempercepat waktu kompilasi dan mengurangi konsumsi memori kompilator bagi 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 menghasilkan kesalahan kompilator jika mendeteksi kata kunci yang telah diganti oleh 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 sesuai dengan apa yang dinyatakan oleh namanya.

  • Untuk menerapkan berbagai pengoptimalan dan pemeriksaan debugging, 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 Visual Studio 2010 dengan yang dikompilasi dengan kompilator C++ di Visual Studio 2012, menghasilkan kesalahan linker tentang ketidakcocokan _MSC_VER, di mana _MSC_VER adalah makro yang berisi versi utama dari kompilator (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 keluarga kontainer std::unordered_map 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 keluarga std::unordered_map telah diperpanjang untuk mencakup keluarga stdext::hash_map. (Kami menyarankan agar Anda menghindari penggunaan stdext::hash_map keluarga dalam kode baru.)

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

CRT

  • Heap Runtime C (CRT), yang digunakan untuk "new" dan malloc(), sekarang publik. 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 untuk Fusion telah dihapus (afxcomctl32.h); karena itu, semua metode yang didefinisikan dalam <afxcomctl32.h> juga 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.

  • Kategori pelacakan ATL yang usang telah dihapus.

  • 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.)

  • API AFXTrackMouse telah dihapus (beserta proseur timer yang 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.

  • Mengganti nama AFX_GLOBAL_DATA::DwmIsCompositionEnabled menjadi IsDwmCompositionEnabled untuk menghilangkan konflik nama.

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

  • Mengubah definisi OnExitSizeMove metode agar sesuai 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 signature OnMouseLeave metode untuk sesuai dengan makro ON_WM_MOUSELEAVE:

    • CMFCCaptionBar

    • CMFCColorBar

    • CMFCHeaderCtrl

    • CMFCProperySheetListBox

    • CMFCRibbonBar

    • CMFCRibbonPanelMenuBar

    • CMFCRibbonRichEditCtrl

    • CMFCSpinButtonCtrl

    • CMFCToolBar GantiTeksIni

    • 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 kelas CPropertyPage, panggil alih-alih GetParent untuk mendapatkan jendela lembar induk yang benar, yang mungkin merupakan jendela induk atau kakek ke CPropertyPage. Anda mungkin harus mengubah kode Anda untuk memanggil GetParentSheet alih-alih GetParent.

  • Memperbaiki ketidakseimbangan penggunaan #pragma warning(push) di ATLBASE.H, yang menyebabkan peringatan dinonaktifkan secara tidak semestinya. Peringatan tersebut sekarang diaktifkan dengan benar setelah ATLBASE.H diuraikan.

  • Memindahkan metode terkait D2D dari AFX_GLOBAL_DATA ke _AFX_D2D_STATE:

    • GetDirectD2dFactory

    • GetWriteFactory

    • GetWICFactory

    • InitD2D

    • ReleaseD2DRefs

    • IsD2DInitialized

    • D2D1MakeRotateMatrix

    • Alih-alih memanggil, contohnya afxGlobalData.IsD2DInitialized, panggil AfxGetD2DState->IsD2DInitialized.

  • Menghapus file-file ATL*.CPP usang dari folder \atlmfc\include\.

  • Memindahkan inisialisasi afxGlobalData ke berdasarkan permintaan daripada pada waktu inisialisasi CRT, untuk memenuhi persyaratan DLLMain.

  • Menambahkan metode RemoveButtonByIndex ke kelas CMFCOutlookBarPane.

  • Telah dikoreksi CMFCCmdUsageCount::IsFreqeuntlyUsedCmd ke IsFrequentlyUsedCmd.

  • Mengoreksi beberapa instans dari RestoreOriginalstate ke RestoreOriginalState (CMFCToolBar, CMFCMenuBar, CMFCOutlookBarPane).

  • Menghapus metode yang tidak digunakan dari CDockablePane: , , SetCaptionStyle, IsDrawCaptionIsHideDisabledButtons, dan GetRecentSiblingPaneInfoCanAdjustLayout.

  • Menghapus variabel anggota statis CDockablePane, m_bCaptionText, 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 tidak mencakup dukungan untuk penggunaan GUID tanpa tanda kutip dalam atribut IDL 'uuid'.

  • .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 rusak secara eksplisit, gunakan pernyataan __try-__except. Atau, terapkan atribut [HandledProcessCorruptedStateExceptions]untuk memungkinkan fungsi menangkap pengecualian status yang rusak. Perubahan ini terutama berdampak pada pemrogram sistem yang mungkin harus menangkap pengecualian keadaan 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 opsi pengkompilasi /GL (Optimisasi Program Keseluruhan) dan /clr (Kompilasi Runtime Bahasa Umum), opsi /GL akan 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 = Dinonaktifkan.

CLR (Common Language Runtime)

  • Pengkompilasi Microsoft C# dan Visual Basic sekarang dapat menghasilkan tanpa perakitan interop utama (tanpa PIA). Rakitan tanpa-PIA dapat menggunakan tipe-tipe COM tanpa harus menyebarkan Primary Interop Assembly (PIA) yang relevan. Saat menggunakan assembly no-PIA yang dihasilkan oleh Visual C# atau Visual Basic, Anda harus mereferensikan assembly PIA pada perintah kompilasi sebelum mereferensikan assembly no-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 tertunda lembar properti. 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 fungsi abort() atau fungsi terminate() menutup versi ritel dari aplikasi, Pustaka C Runtime menampilkan pesan penghentian aplikasi di jendela konsol atau sekotak pesan di 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 signifikan hanya jika Anda bergantung pada perilaku pesan penghentian aplikasi sebelumnya.

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

Pustaka

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

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

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

  • CComPtr::CComPtr(int) konstruktor dihapus. Konstruktor tersebut memungkinkan objek CComPtr dibangun dari makro NULL, tetapi tidak perlu dan mengizinkan konstruksi yang tidak masuk akal dari bilangan bulat bukan nol.

    CComPtr masih dapat dibangun dari NULL, yang didefinisikan sebagai 0, tetapi akan gagal jika dibangun dari bilangan bulat yang bukan 0 literal. 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.

  • Nomor urut tidak lagi digunakan kembali dalam file modul-definisi (.def) MFC. Perubahan ini berarti urutan ordinal tidak akan berbeda antara versi minor, dan kompatibilitas biner untuk paket layanan serta rilis rekayasa perbaikan cepat akan ditingkatkan.

  • Fungsi virtual baru ditambahkan ke CDocTemplate kelas . Fungsi virtual baru ini adalah CDocTemplate Class. Versi sebelumnya dari OpenDocumentFile memiliki 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, .286P.287, .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:

    • penghitung_kinerja

    • perf_object

    • perfmon

    • pengelola permintaan

    • penangan sabun

    • soap_header

    • metode_soap

    • nama_tag

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, pengatur 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 .

  • 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 akan mengonsumsi semuanya. Sekarang, do_get berhenti mengurai setelah memproses paling banyak 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 menyebabkan kerusakan pada kode yang melewati parameter tidak valid dan bergantung pada fungsi untuk mengabaikannya atau sekadar 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. Flag /ML pengkompilasi tidak lagi didukung. Versi non-penguncian dari beberapa fungsi telah ditambahkan dalam kasus di mana perbedaan performa antara kode multi-utas dan kode utas tunggal berpotensi signifikan.

  • Varian kelebihan fungsi pow, yaitu 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 bertanda.

  • 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 ditetapkan).

  • _spawn, _wspawn Functions sekarang tidak menyentuh errno ketika berhasil, sesuai 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 pointer konstan. 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 kartubebas 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 ruang nama std. Di versi sebelumnya, kelas ini berada di namespace 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.

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

Perubahan Signifikan Visual C++ .NET 2003

Kompilator

  • Penutupan tanda kurung sekarang diwajibkan untuk direktif 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 destruktor dan/atau konstruktor penyalin 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 tidak diizinkan oleh standar dan sekarang menyebabkan kesalahan kompilasi (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 friend tidak lagi diperkenalkan dalam namespace yang memuat (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).

Lihat juga

Yang Baru untuk Visual C++ di Visual Studio