Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Microsoft C/C++ di Visual Studio (MSVC) melakukan peningkatan kesesuaian dan perbaikan bug di setiap rilis. Artikel ini mencantumkan peningkatan signifikan berdasarkan rilis utama, lalu berdasarkan versi. Untuk melompat langsung ke perubahan untuk versi tertentu, gunakan tautan Di artikel ini di bagian atas artikel ini.
Dokumen ini mencantumkan perubahan di Visual Studio 2022.
Untuk perubahan di versi Visual Studio yang lebih lama:
| Versi | Tautan untuk penyempurnaan kepatuhan |
|---|---|
| 2019 | Peningkatan kesuaian C++ di Visual Studio 2019 |
| 2017 | Peningkatan kesuaian C++ di Visual Studio 2017 |
| 2003-2015 | Visual C++ yang Baru 2003 hingga 2015 |
Peningkatan kesuaian di Visual Studio 2022 versi 17.14
Visual Studio 2022 versi 17.14 mencakup peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Peningkatan kesesuaian
- Penguatan pustaka standar (P3471R4) mengubah beberapa contoh perilaku yang tidak ditentukan di pustaka standar menjadi panggilan ke __fastfail. Nonaktif secara default. Tentukan
_MSVC_STL_HARDENING=1di seluruh proyek untuk mengaktifkannya.
Perilaku yang lebih baik
- Menerapkan "batu nisan destruktor" untuk mengurangi kesalahan penggunaan setelah bebas. Nonaktif secara default. Tentukan
_MSVC_STL_DESTRUCTOR_TOMBSTONES=1di seluruh proyek untuk mengaktifkannya.
Pemulihan kesalahan perangkat lunak
Memperbaiki kesalahan kompilator yang salah saat menggunakan
<format>dalam proyek CUDA.Memperbaiki masalah kompilator di mana alamat variabel lokal dapat "bocor" selama
constexprevaluasi. Contohnya:const unsigned & func() { const int x = 0; constexpr const unsigned & r1 = x; // Previously accepted, now an error return r1; } auto r = func(); // Previously, the local address leakedContoh #2
#include <initializer_list> void test() { constexpr std::initializer_list<int> xs { 1, 2, 3 }; // Previously accepted, now an error static constexpr std::initializer_list<int> ys { 1, 2, 3 }; // Correct usage - note use of static }Kode yang dikompilasi dengan
/permissive-tidak lagi menerima kombinasifrienddanstaticpada deklarasi. Perbaikan biasanya dihapusstaticdari deklarasi. Contohnya:struct S { friend static void f(); // Previously accepted, now emits error C2440: 'static' cannot be used with 'friend' };Pengikatan referensi ke jenis yang memenuhi syarat volatil diperbaiki saat mengacu pada kelas dasar atau turunan. Contohnya:
struct A {}; struct B : public A {}; void f(A&); // 1 void f(const volatile A&); // 2 f(B{}); // Previously called 2. This is ill-formed under /permissive- or /Zc:referenceBinding. Chooses 1 if relaxed reference binding rules are enabled.
Untuk ringkasan mendalam perubahan yang dilakukan pada Pustaka Templat Standar, termasuk perubahan kesesuaian, perbaikan bug, dan peningkatan performa, lihat STL Changelog VS 2022 17.14.
Peningkatan kesuaian di Visual Studio 2022 versi 17.13
Visual Studio 2022 versi 17.13 mencakup peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Untuk ringkasan mendalam perubahan yang dilakukan pada Pustaka Templat Standar, termasuk perubahan kesesuaian, perbaikan bug, dan peningkatan performa, lihat STL Changelog VS 2022 17.13.
Pencarian tergantung argumen (ADL)
Konstruksi bahasa seperti loop range-for dan pengikatan terstruktur memiliki aturan pencarian khusus yang bergantung pada argumen untuk pengidentifikasi tertentu seperti begin, end, atau get. Sebelumnya, pencarian ini menyertakan kandidat dari std namespace, bahkan ketika namespace std bukan bagian dari kumpulan namespace terkait biasa untuk pencarian yang bergantung pada argumen.
Program yang memperkenalkan deklarasi ke std untuk konstruksi-konstruksi ini tidak dapat lagi dikompilasi. Sebaliknya, deklarasi harus berada di namespace terkait yang normal untuk tipe yang terlibat (mungkin termasuk namespace global).
template <typename T>
struct Foo {};
namespace std
{
// To correct the program, move these declarations from std to the global namespace
template <typename T>
T* begin(Foo<T>& f);
template <typename T>
T* end(Foo<T>& f);
}
void f(Foo<int> foo)
{
for (auto x : foo) // Previously compiled. Now emits error C3312: no callable 'begin' function found for type 'Foo<int>'
{
...
}
}
Tidak dapat mengubah makro yang dicadangkan oleh implementasi
Sebelumnya, kompiler mengizinkan perubahan atau menghapus pendefinisian makro tertentu yang disediakan oleh implementasi seperti _MSC_EXTENSIONS. Mengubah definisi makro tertentu dapat mengakibatkan perilaku yang tidak terdefinisi.
Mencoba mengubah atau menghapus nama makro tertentu yang terlarang sekarang menghasilkan peringatan tingkat-1 C5308. Dalam mode /permissive-, peringatan ini diperlakukan sebagai kesalahan.
#undef _MSC_EXTENSIONS // Warning C5308: Modifying reserved macro name `_MSC_EXTENSIONS` may cause undefined behavior
Peningkatan kesuaian di Visual Studio 2022 versi 17.12
Visual Studio 2022 versi 17.12 mencakup peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Untuk ringkasan mendalam tentang perubahan yang dilakukan pada Pustaka Templat Standar, termasuk perubahan kesesuaian, perbaikan bug, dan peningkatan performa, lihat STL Changelog VS 2022 17.12.
_com_ptr_t::operator bool() menjadi eksplisit sekarang
Ini adalah perubahan yang memutus kompatibilitas sumber/biner.
Konversi implisit ke bool dari _com_ptr_t instans dapat mengejutkan atau menyebabkan kesalahan kompilator.
C.164: Hindari operator konversi implisit dalam C++ Core Guidelines mencegah fungsi konversi implisit. Dan _com_ptr_t berisi konversi implisit ke bool dan Interface*. Kedua konversi implisit ini dapat menyebabkan ambiguitas.
Untuk mengatasi hal ini, konversi ke bool sekarang eksplisit. Konversi ke Interface* tidak berubah.
Makro disediakan untuk menolak perilaku baru ini dan memulihkan konversi implisit sebelumnya. Kompilasi dengan /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL untuk menolak perubahan ini. Kami menyarankan agar Anda mengubah kode agar tidak mengandalkan konversi implisit.
Contohnya:
#include <comip.h>
template<class Iface>
using _com_ptr = _com_ptr_t<_com_IIID<Iface, &__uuidof(Iface)>>;
int main()
{
_com_ptr<IUnknown> unk;
if (unk) // Still valid
{
// ...
}
bool b = unk; // Still valid.
int v = unk; // Previously permitted, now emits C2240: cannot convert from '_com_ptr_t<_com_IIID<IUnknown,& _GUID_00000000_0000_0000_c000_000000000046>>' to 'int'
}
Ekspresi konstanta tidak lagi selalu noexcept dalam mode permisif
Ini adalah perubahan yang memutus kompatibilitas sumber/biner.
Ekspresi konstanta senantiasa bernilai noexcept, bahkan jika melibatkan pemanggilan fungsi ke fungsi yang dideklarasikan dengan spesifikasi pengecualian yang mungkin melempar. Kata-kata ini dihapus di C++17, meskipun pengkompilasi Microsoft Visual C++ masih mendukungnya dalam /permissive mode di semua versi bahasa C++.
Perilaku mode ini /permissive dihentikan. Ekspresi konstanta tidak lagi diberi perilaku implisit khusus.
Penentu noexcept pada fungsi constexpr sekarang dipatuhi di semua mode. Perubahan ini diperlukan untuk implementasi resolusi masalah inti selanjutnya yang bergantung pada perilaku standar noexcept.
Contohnya:
constexpr int f(bool b) noexcept(false)
{
if (b)
{
throw 1;
}
else
{
return 1;
}
}
void g(bool b)
{
noexcept(f(b)); // false. No change to behavior
noexcept(f(true)); // false. No change to behavior
noexcept(f(false)); // false. Was true in /permissive mode only in previous versions.
}
Peningkatan kesuaian di Visual Studio 2022 versi 17.11
Visual Studio 2022 versi 17.11 mencakup peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Untuk ringkasan mendalam perubahan yang dilakukan pada Pustaka Templat Standar, termasuk perubahan kesesuaian, perbaikan bug, dan peningkatan performa, lihat STL Changelog VS 2022 17.11.
Cetak baris kosong dengan println
Per P3142R0, sekarang mudah untuk menghasilkan baris kosong dengan println. Fitur ini tersedia saat mengkompilasi dengan /std:c++latest.
Sebelum perubahan ini, Anda menulis: println(""); Sekarang Anda menulis: println();.
-
println();setara denganprintln(stdout); -
println(FILE* stream);setara denganprintln(stream, "\n");
Dilaksanakan range_formatter
Berdasarkan P2286R8, range_formatter sekarang diimplementasikan. Fitur ini tersedia saat mengkompilasi dengan /std:c++latest.
Peningkatan kesuaian di Visual Studio 2022 versi 17.10
Visual Studio 2022 versi 17.10 mencakup peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Untuk ringkasan mendalam perubahan yang dilakukan pada Pustaka Templat Standar, termasuk perubahan kesesuaian, perbaikan bug, dan peningkatan performa, lihat STL Changelog VS 2022 17.10.
Spesialisasi operator konversi dengan jenis pengembalian yang ditentukan secara eksplisit
Pengkompilasi kadang-kadang mengkhususkan operasi konversi dengan cara yang salah, yang dapat menyebabkan jenis pengembalian tidak cocok. Spesialisasi yang tidak valid ini tidak lagi terjadi. Ini adalah perubahan pemecahan kode sumber.
// Example 1
struct S
{
template<typename T> operator const T*();
};
void test()
{
S{}.operator int*(); // this is invalid now
S{}.operator const int*(); // this is valid
}
// Example 2
// In some cases, the overload resolution result may change
struct S
{
template <typename T> operator T*(); // overload 1
template <typename T> operator const T*(); // overload 2
};
void test()
{
S{}.operator int*(); // this used to call overload 2, now it calls overload 1
}
Menambahkan Dukungan untuk #elifdef dan #elifndef
Dukungan ditambahkan untuk WG21 P2334R1 (C++23) dan WG14 N2645 (C++23) yang memperkenalkan #elifdef arahan prapemroseduran dan #elifndef .
Memerlukan /std:clatest atau /std:c++latest.
Sebelum:
#ifdef __cplusplus
#include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Setelah:
#ifdef __cplusplus
#include <atomic>
#elifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Penerapan _Alignas pada tipe terstruktur di C
Berlaku untuk bahasa C (C17 dan yang lebih baru). Juga ditambahkan ke Microsoft Visual Studio 17.9
Dalam versi Visual C++ sebelum Visual Studio 2022 versi 17.9, jika penentu _Alignas muncul di samping jenis terstruktur dalam deklarasi, itu tidak diaplikasikan dengan tepat sesuai dengan Standar ISO-C.
// compile with /std:c17
#include <stddef.h>
struct Outer
{
_Alignas(32) struct Inner { int i; } member1;
struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");
Menurut standar ISO-C, kode ini harus dikompilasi tanpa static_assert menghasilkan diagnosis.
Direktif _Alignas hanya berlaku untuk variabel anggota member1. Ini tidak boleh mengubah perataan struct Inner. Namun, sebelum Visual Studio 17.9.1, diagnostik "penyelarasan yang salah" muncul. Compiler menyelaraskan member2 dengan offset 32 byte dalam jenis struct Outer.
Ini adalah perubahan yang memutuskan kompatibilitas biner, sehingga peringatan akan dikeluarkan ketika perubahan ini berlaku. Peringatan C5274 sekarang dipancarkan pada tingkat peringatan 1 untuk contoh sebelumnya: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).
Selain itu, di versi Visual Studio sebelumnya, ketika penentu _Alignas muncul di samping deklarasi jenis anonim, itu diabaikan.
// compile with /std:c17
#include <stddef.h>
struct S
{
_Alignas(32) struct { int anon_member; };
int k;
};
static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");
Sebelumnya, kedua static_assert pernyataan gagal saat mengkompilasi kode ini. Sekarang kode dikompilasi, tetapi memancarkan peringatan tingkat 1 berikut:
warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)
Untuk mendapatkan perilaku sebelumnya, ganti _Alignas(N) dengan __declspec(align(N)). Tidak seperti _Alignas, declspec(align) berlaku untuk jenis .
Peningkatan peringatan C4706
Ini adalah perubahan pemecahan kode sumber. Sebelumnya, pengompilasi tidak mendeteksi konvensi membungkus penugasan dalam tanda kurung, jika memang dimaksudkan untuk menugaskan, untuk menghilangkan peringatan C4706 tentang penugasan dalam ekspresi kondisional. Pengompilasi sekarang mendeteksi tanda kurung dan menekan peringatan.
#pragma warning(error: 4706)
struct S
{
auto mf()
{
if (value = 9)
return value + 4;
else
return value;
}
int value = 9;
};
Pengkompilasi sekarang juga memancarkan peringatan dalam kasus di mana fungsi tidak dirujuk. Sebelumnya, karena mf adalah fungsi sebaris yang tidak dirujuk, peringatan C4706 tidak dipancarkan untuk kode ini. Sekarang peringatan dipancarkan:
error C4706: assignment used as a condition
note: if an assignment is intended you can enclose it in parentheses, '(e1 = e2)', to silence this warning
Untuk memperbaiki peringatan ini, gunakan operator kesetaraan, value == 9, jika ini yang dimaksudkan. Atau, bungkus tugas dalam tanda kurung, (value = 9), jika penugasan dimaksudkan. Jika tidak, karena fungsi tidak direferensikan, hapus.
Peningkatan kesuaian di Visual Studio 2022 versi 17.9
Visual Studio 2022 versi 17.9 berisi peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Untuk ringkasan perubahan yang lebih luas yang dibuat pada Pustaka Templat Standar, lihat STL Changelog VS 2022 17.9.
Penerapan _Alignas pada tipe terstruktur di C
Dalam versi Visual C++ sebelum Visual Studio 2022 versi 17.9, ketika _Alignas muncul di samping jenis struktur dalam deklarasi, itu tidak diterapkan dengan benar sesuai dengan Standar ISO-C. Contohnya:
// compile with /std:c17
#include <stddef.h>
struct Outer
{
_Alignas(32) struct Inner { int i; } member1;
struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");
Menurut Standar ISO-C, kode ini harus dikompilasi tanpa mengeluarkan pesan diagnostik. Direktif _Alignas hanya berlaku untuk variabel anggota member1. Ini tidak boleh mengubah perataan struct Inner. Namun, sebelum rilis 17.9.1 Visual Studio, diagnostik "penyelarasan yang salah" dikeluarkan. Pengkompilasi menyetel member2 ke offset 32 byte di dalam struct Outer.
Memperbaiki ini merupakan perubahan yang memutus kompatibilitas biner, jadi ketika perubahan perilaku ini diterapkan, peringatan akan dikeluarkan. Untuk kode sebelumnya, Peringatan C5274, "_Alignas tidak lagi berlaku untuk jenis 'Inner' (hanya berlaku untuk objek data yang dideklarasikan)" sekarang dikeluarkan pada level peringatan 1.
Di versi Visual Studio sebelumnya, _Alignas diabaikan ketika muncul di samping deklarasi jenis anonim. Contohnya:
// compile with /std:c17
#include <stddef.h>
struct S {
_Alignas(32) struct { int anon_member; };
int k;
};
static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");
Sebelumnya, kedua static_assert pernyataan gagal saat mengkompilasi kode ini. Kode sekarang dikompilasi, tetapi dengan peringatan tingkat 1 berikut:
warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)
Jika Anda menginginkan perilaku sebelumnya, ganti _Alignas(N) dengan __declspec(align(N)). Tidak seperti _Alignas, declspec(align) dapat diterapkan ke jenis.
__VA_OPT__ diaktifkan sebagai ekstensi di bawah /Zc:preprocessor
__VA_OPT__ ditambahkan ke C++20 dan C23. Sebelum ditambahkan, tidak ada cara standar untuk menghilangkan koma dalam makro variadis. Untuk memberikan kompatibilitas mundur yang lebih baik, __VA_OPT__ diaktifkan di bawah praprosesor /Zc:preprocessor berbasis token di semua versi bahasa.
Misalnya, sekarang ini dikompilasi tanpa kesalahan:
#define LOG_WRAPPER(message, ...) WRITE_LOG(__LINE__, message __VA_OPT__(, __VA_ARGS__))
// Failed to build under /std:c11, now succeeds.
LOG_WRAPPER("Log message");
LOG_WRAPPER("Log message with %s", "argument")
Bahasa C23
Untuk C23, berikut ini tersedia saat menggunakan opsi pengalih kompilator /std:clatest:
Berikut ini tersedia untuk semua versi bahasa C:
Pustaka Standar C++
Fitur C++23
-
formattable,range_format,format_kind, danset_debug_format()sebagai bagian dari Rentang Pemformatan P2286R8 -
<mdspan>sesuai dengan P0009R18 dan perubahan kata-kata berikutnya yang diterapkan pada Standar C++23. -
format()penunjuk per P2510R3.
Peningkatan kesuaian di Visual Studio 2022 versi 17.8
Visual Studio 2022 versi 17.8 berisi peningkatan kesesuaian, perbaikan bug, dan perubahan perilaku berikut dalam kompilator Microsoft C/C++.
/FU menampilkan kesalahan
Pengompiler C dulunya menerima opsi /FU, meskipun telah lama tidak mendukung kompilasi terkelola. Sekarang mengeluarkan kesalahan. Proyek yang meneruskan opsi ini hanya perlu membatasinya ke proyek C++/CLI.
Pustaka Standar C++
Modul bernama C++23 std dan std.compat sekarang tersedia saat mengompilasi dengan /std:c++20.
Untuk ringkasan perubahan yang lebih luas yang dilakukan pada Pustaka Standar C++, lihat STL Changelog VS 2022 17.8.
Peningkatan kesuaian di Visual Studio 2022 versi 17.7
Visual Studio 2022 versi 17.7 berisi peningkatan kesesuaian yang disorot berikut, perbaikan bug, dan perubahan perilaku di pengompilasi Microsoft C/C++.
Ditambahkan /std:clatest ke pengkompilasi C
Sakelar ini berfungsi seperti sakelar /std:c++latest untuk kompilator C++. Saklar ini mengaktifkan semua fitur dari kompiler dan fitur pustaka standar yang saat ini diimplementasikan serta diusulkan untuk standar draf C berikutnya, termasuk beberapa fitur yang masih dalam pengembangan dan bersifat eksperimental.
Pustaka Standar C++
<print> Perpustakaan sekarang didukung. Lihat Output Terformat P2093R14.
Telah diimplementasikan views::cartesian_product.
Untuk ringkasan perubahan yang lebih luas yang dibuat pada Pustaka Templat Standar, lihat STL Changelog VS 2022 17.7.
using Kesesuaian
Sebelumnya, arahan using dapat menyebabkan nama dari namespace yang digunakan tetap terlihat ketika seharusnya tidak. Ini dapat menyebabkan pencarian nama tanpa kualifikasi untuk menemukan nama di namespace bahkan ketika tidak ada direktif using yang aktif.
Berikut adalah beberapa contoh perilaku baru dan lama.
Referensi dalam komentar berikut ke "(1)" berarti panggilan ke f<K>(t) di namespace A:
namespace A
{
template<typename K, typename T>
auto f2(T t)
{
return f<K>(t); // (1) Unqualified lookup should not find anything
}
}
namespace B
{
template<typename K, typename T>
auto f(T t) noexcept
{ // Previous behavior: This function was erroneously found during unqualified lookup at (1)
return A::f2<K>(t);
}
}
namespace C
{
template<typename T>
struct S {};
template<typename, typename U>
U&& f(U&&) noexcept; // New behavior: ADL at (1) correctly finds this function
}
namespace D
{
using namespace B;
void h()
{
D::f<void>(C::S<int>());
}
}
Masalah yang mendasar yang sama dapat menyebabkan kode yang sebelumnya dikompilasi sekarang ditolak:
#include <memory>
namespace Addin {}
namespace Gui
{
using namespace Addin;
}
namespace Addin
{
using namespace std;
}
// This previously compiled, but now emits error C2065 for undeclared name 'allocator'.
// This should be declared as 'std::allocator<T*>' because the using directive nominating
// 'std' is not active at this point.
template <class T, class U = allocator<T*>>
class resource_list
{
};
namespace Gui
{
typedef resource_list<int> intlist;
}
Peningkatan kesuaian di Visual Studio 2022 versi 17.6
Visual Studio 2022 versi 17.6 berisi peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam kompilator Microsoft C/C++.
Penugasan gabungan volatile tidak lagi usang
C++20 tidak lagi merekomendasikan penerapan operator tertentu pada tipe yang memenuhi syarat dengan volatile. Misalnya, ketika kode berikut dikompilasi dengan cl /std:c++20 /Wall test.cpp:
void f(volatile int& expr)
{
++expr;
}
Pengkompilasi menghasilkan test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20.
Di C++20, operator penugasan gabungan (operator formulir @=) tidak digunakan lagi. Di C++23, operator senyawa yang dikecualikan di C++20 sekarang tidak lagi dianggap usang. Misalnya, di C++23 kode berikut tidak menghasilkan peringatan, sedangkan kode ini terjadi di C++20:
void f(volatile int& e1, int e2)
{
e1 += e2;
}
Untuk informasi selengkapnya tentang perubahan ini, lihat CWG:2654
Menulis ulang kesetaraan dalam ekspresi kurang dari modifikasi yang signifikan (P2468R2)
Di C++20, P2468R2 mengubah pengkompilasi untuk menerima kode seperti:
struct S
{
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} != S{};
Pengkompilasi menerima kode ini, yang berarti bahwa pengkompilasi lebih ketat dengan kode seperti:
struct S
{
operator bool() const;
bool operator==(const S&);
};
bool b = S{} == S{};
Versi 17.5 pengkompilasi menerima program ini. Compiler versi 17.6 menolaknya. Untuk memperbaikinya, tambahkan const ke operator== untuk menghapus ambiguitas. Atau, tambahkan operator!= yang sesuai ke dalam definisi seperti ditunjukkan dalam contoh berikut:
struct S
{
operator bool() const;
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} == S{};
Pengkompilasi Microsoft C/C++ versi 17.5 dan 17.6 menerima program sebelumnya, dan memanggil S::operator== di kedua versi.
Model pemrograman umum yang diuraikan dalam P2468R2 adalah bahwa jika ada operator!= yang sesuai untuk tipe, biasanya menghentikan perilaku penulisan ulang. Menambahkan yang sesuai operator!= adalah perbaikan yang disarankan untuk kode yang sebelumnya dikompilasi di C++17. Untuk informasi selengkapnya, lihat Model Pemrograman.
Peningkatan kesuaian di Visual Studio 2022 versi 17.4
Visual Studio 2022 versi 17.4 berisi peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Jenis dasar yang tidak terlingkup enum tanpa tipe tetap
Dalam versi Visual Studio sebelum Visual Studio 2022 versi 17.4, kompilator C++ tidak dengan benar menentukan jenis dasar dari enumerasi yang tidak terlingkup tanpa jenis dasar tetap. Di bawah /Zc:enumTypes, kami sekarang menerapkan perilaku standar dengan benar.
Standar C++ mengharuskan tipe dasar dari enum cukup besar untuk memuat semua enumerator dalam enum. Enumerator yang cukup besar dapat mengatur jenis dasar dari enum ke unsigned int, long long, atau unsigned long long. Sebelumnya, jenis tersebut enum selalu memiliki tipe dasar int dalam kompilator Microsoft, tanpa memedulikan nilai enumerator.
Saat diaktifkan, opsi /Zc:enumTypes adalah sumber perubahan dan pemecahan biner yang potensial. Ini nonaktif secara default, dan tidak diaktifkan oleh /permissive-, karena perbaikan dapat memengaruhi kompatibilitas biner. Beberapa jenis enumerasi berubah ukuran ketika perbaikan yang sesuai diaktifkan. Header Windows SDK tertentu menyertakan definisi enumerasi tersebut.
Contoh
enum Unsigned
{
A = 0xFFFFFFFF // Value 'A' does not fit in 'int'.
};
// Previously, failed this static_assert. Now passes with /Zc:enumTypes.
static_assert(std::is_same_v<std::underlying_type_t<Unsigned>, unsigned int>);
template <typename T>
void f(T x)
{
}
int main()
{
// Previously called f<int>, now calls f<unsigned int>.
f(+A);
}
// Previously this enum would have an underlying type of `int`, but Standard C++ requires this to have
// a 64-bit underlying type. Using /Zc:enumTypes changes the size of this enum from 4 to 8, which could
// impact binary compatibility with code compiled with an earlier compiler version or without the switch.
enum Changed
{
X = -1,
Y = 0xFFFFFFFF
};
Jenis enumerator dalam enum definisi tanpa jenis dasar tetap
Dalam versi Visual Studio sebelum Visual Studio 2022 versi 17.4, kompilator C++ tidak memodelkan jenis enumerator dengan benar. Ini dapat mengasumsikan jenis yang salah dalam enumerasi tanpa jenis dasar yang tetap sebelum kurung kurawal penutup dari enumerasi. Di bawah /Zc:enumTypes, pengkompilasi sekarang mengimplementasikan perilaku standar dengan benar.
Standar C++ menentukan bahwa dalam definisi enumerasi tanpa jenis dasar tetap, penginisialisasi menentukan jenis enumerator. Atau, untuk enumerator tanpa inisialisasi, berdasarkan tipe enumerator sebelumnya (memperhitungkan kelebihan). Sebelumnya, enumerator seperti itu selalu diberi jenis enumerasi yang disimpulkan, dengan tempat penampung untuk jenis dasar (biasanya int).
Saat diaktifkan, opsi /Zc:enumTypes adalah sumber perubahan dan pemecahan biner yang potensial. Ini nonaktif secara default, dan tidak diaktifkan oleh /permissive-, karena perbaikan dapat memengaruhi kompatibilitas biner. Beberapa jenis enumerasi berubah ukuran ketika perbaikan yang sesuai diaktifkan. Header Windows SDK tertentu menyertakan definisi enumerasi tersebut.
Contoh
enum Enum {
A = 'A',
B = sizeof(A)
};
static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes
Dalam contoh ini, enumerator A harus memiliki tipe char sebelum kurung kurawal penutup enumerasi, maka B harus diinisialisasi menggunakan sizeof(char).
/Zc:enumTypes Sebelum perbaikan, A memiliki jenis enumerasi Enum dengan jenis dasar int yang disimpulkan, dan B diinisialisasi menggunakan sizeof(Enum), atau 4.
Peningkatan kesuaian di Visual Studio 2022 versi 17.3
Visual Studio 2022 versi 17.3 berisi peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
C: Peningkatan pemeriksaan kompatibilitas pengubah antara pointer
Pengkompilasi C tidak membandingkan pengubah dengan benar antara penunjuk, terutama void*. Cacat ini dapat mengakibatkan diagnosis ketidakcocokan yang tidak tepat antara const int** dan void* dan kompatibilitas antara int* volatile* dan void*.
Contoh
void fn(void* pv) { (pv); }
int main()
{
int t = 42;
int* pt = &t;
int* volatile * i = &pt;
fn(i); // Now raises C4090
const int** j = &pt;
fn(j); // No longer raises C4090
}
Peningkatan kesesuaian di Visual Studio 2022 versi 17.2
Visual Studio 2022 versi 17.2 berisi peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Peringatan karakter dua arah yang tidak tertutup
Visual Studio 2022 versi 17.2 menambahkan peringatan tingkat 3 C5255 untuk karakter dua arah Unicode tanpa henti dalam komentar dan string. Peringatan tersebut membahas masalah keamanan yang dijelaskan dalam Sumber Trojan: Kerentanan Tak Terlihat oleh Nicholas Boucher dan Ross Anderson. Untuk informasi selengkapnya tentang karakter dua arah Unicode, lihat Lampiran Standar Unicode® #9: ALGORITMA DUA ARAH UNICODE.
Peringatan C5255 hanya membahas file yang, setelah konversi, berisi karakter dua arah Unicode. Peringatan ini berlaku untuk file UTF-8, UTF-16, dan UTF-32, sehingga pengodean sumber yang tepat harus disediakan. Perubahan ini adalah perubahan yang merusak sumber.
Contoh (sebelum/sesudah)
Dalam versi Visual Studio sebelum Visual Studio 2022 versi 17.2, karakter dua arah yang tidak diakhiri tidak menghasilkan peringatan. Visual Studio 2022 versi 17.2 menghasilkan peringatan C5255:
// bidi.cpp
int main() {
const char *access_level = "user";
// The following source line contains bidirectional Unicode characters equivalent to:
// if ( strcmp(access_level, "user\u202e \u2066// Check if admin \u2069 \u2066") ) {
// In most editors, it's rendered as:
// if ( strcmp(access_level, "user") ) { // Check if admin
if ( strcmp(access_level, "user // Check if admin ") ) {
printf("You are an admin.\n");
}
return 0;
}
/* build output
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+202e'
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+2066'
*/
from_chars()
float pemecah tiebreaker
Visual Studio 2022 versi 17.2 memperbaiki bug dalam <charconv>from_chars()float aturan pemisah yang menghasilkan hasil yang salah. Bug ini memengaruhi string desimal yang ada di titik tengah yang tepat dari nilai float berturut-turut, dalam rentang sempit. (Nilai terkecil dan terbesar yang terpengaruh adalah 32768.009765625 dan 131071.98828125 masing-masing.) Aturan tiebreaker ingin membulatkan ke "genap," dan "genap" kebetulan menjadi "turun," tetapi implementasi salah membulatkan menjadi "ke atas" (double tidak terpengaruh.) Untuk informasi selengkapnya dan detail implementasi, lihat microsoft/STL#2366.
Perubahan ini memengaruhi perilaku runtime dalam rentang kasus yang ditentukan:
Contoh
// from_chars_float.cpp
#include <cassert>
#include <charconv>
#include <cstdio>
#include <string_view>
#include <system_error>
using namespace std;
int main() {
const double dbl = 32768.009765625;
const auto sv = "32768.009765625"sv;
float flt = 0.0f;
const auto result = from_chars(sv.data(), sv.data() + sv.size(), flt);
assert(result.ec == errc{});
printf("from_chars() returned: %.1000g\n", flt);
printf("This rounded %s.\n", flt < dbl ? "DOWN" : "UP");
}
Dalam versi sebelum Visual Studio 2022 versi 17.2:
C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.01171875
This rounded UP.
Dalam Visual Studio 2022 versi 17.2 dan yang lebih baru:
C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.0078125
This rounded DOWN.
/Zc:__STDC__ memungkinkan __STDC__ tersedia untuk C
Standar C mengharuskan implementasi C yang sesuai mendefinisikan __STDC__ sebagai 1. Karena perilaku UCRT, yang tidak mengekspos fungsi POSIX ketika __STDC__ adalah 1, tidak dimungkinkan untuk menentukan makro ini untuk C secara default tanpa memperkenalkan perubahan mencolok ke versi bahasa yang stabil. Visual Studio 2022 versi 17.2 dan yang lebih baru menambahkan opsi /Zc:__STDC__ kesesuaian yang menentukan makro ini. Tidak ada versi negatif dari opsi ini. Saat ini, kami berencana untuk menggunakan opsi ini secara default untuk versi C pada waktu mendatang.
Perubahan ini adalah perubahan yang merusak sumber. Ini berlaku ketika mode C11 atau C17 diaktifkan (/std:c11 atau /std:c17) dan /Zc:__STDC__ ditentukan.
Contoh
// test__STDC__.c
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
int main() {
#if __STDC__
int f = _open("file.txt", _O_RDONLY);
_close(f);
#else
int f = open("file.txt", O_RDONLY);
close(f);
#endif
}
/* Command line behavior
C:\Temp>cl /EHsc /W4 /Zc:__STDC__ test__STDC__.c && test__STDC__
*/
Peringatan tanda kurung kurawal hilang
Peringatan C5246 melaporkan hilangnya kurung kurawal selama penginisialisasian agregat pada subobjek. Sebelum Visual Studio 2022 versi 17.2, peringatan tidak menangani kasus anonim struct atau union.
Perubahan ini adalah perubahan yang merusak sumber. Ini berlaku ketika peringatan off-by-default C5246 diaktifkan.
Contoh
Di Visual Studio 2022 versi 17.2 dan yang lebih baru, kode ini sekarang menyebabkan kesalahan:
struct S {
union {
float f[4];
double d[2];
};
};
void f()
{
S s = { 1.0f, 2.0f, 3.14f, 4.0f };
}
/* Command line behavior
cl /Wall /c t.cpp
t.cpp(10): warning C5246: 'anonymous struct or union': the initialization of a subobject should be wrapped in braces
*/
Untuk mengatasi masalah ini, gunakan kurung kurawal pada penginisialisasi:
void f()
{
S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Peningkatan kesesuaian di Visual Studio 2022 versi 17.1
Visual Studio 2022 versi 17.1 berisi peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Mendeteksi default penangkapan yang salah bentuk dalam ekspresi lambda nonlokal
Standard C++ hanya memungkinkan ekspresi lambda dalam cakupan blok memiliki *capture-default*. Di Visual Studio 2022 versi 17.1 dan yang lebih baru, kompilator mendeteksi ketika default penangkapan tidak diperbolehkan pada ekspresi lambda nonlokal. Ini memancarkan peringatan tingkat 4 baru, C5253.
Perubahan ini adalah perubahan yang merusak sumber. Ini berlaku dalam mode apa pun yang menggunakan prosesor lambda baru: /Zc:lambda, /std:c++20, atau /std:c++latest.
Contoh
Di Visual Studio 2022 versi 17.1 kode ini sekarang mengeluarkan kesalahan:
#pragma warning(error:5253)
auto incr = [=](int value) { return value + 1; };
// capture_default.cpp(3,14): error C5253: a nonlocal lambda cannot have a capture default
// auto incr = [=](int value) { return value + 1; };
// ^
Untuk memperbaiki masalah ini, hapus pengaturan pengambilan default.
#pragma warning(error:5253)
auto incr = [](int value) { return value + 1; };
C4028 sekarang menjadi C4133 untuk operasi pengubahan fungsi ke pointer
Sebelum Visual Studio 2022 versi 17.1, pengompilasi melaporkan pesan kesalahan yang salah pada perbandingan pointer-to-function tertentu dalam kode C. Pesan yang salah dilaporkan ketika Anda membandingkan dua pointer fungsi yang memiliki jumlah argumen yang sama tetapi jenis yang tidak kompatibel. Sekarang, kami mengeluarkan peringatan berbeda yang menunjukkan ketidakcocokan pointer-to-function daripada ketidakcocokan parameter fungsi.
Perubahan ini adalah perubahan yang merusak sumber. Ini berlaku ketika kode dikompilasi sebagai C.
Contoh
int f1(int);
int f2(char*);
int main(void)
{
return (f1 == f2);
}
// Old warning:
// C4028: formal parameter 1 different from declaration
// New warning:
// C4113: 'int (__cdecl *)(char *)' differs in parameter lists from 'int (__cdecl *)(int)'
Kesalahan pada yang tidak bergantung static_assert
Di Visual Studio 2022 versi 17.1 dan yang lebih baru, jika ekspresi yang terkait dengan static_assert bukan ekspresi dependen, pengkompilasi mengevaluasi ekspresi ketika dievaluasi. Jika ekspresi dievaluasi menjadi false, pengompilasi menghasilkan kesalahan. Sebelumnya, jika static_assert berada dalam isi templat fungsi (atau dalam isi fungsi anggota templat kelas), pengompilasi tidak akan melakukan analisis ini.
Perubahan ini adalah perubahan yang merusak sumber. Ini berlaku dalam mode apa pun yang menyiratkan /permissive- atau /Zc:static_assert. Perubahan perilaku ini dapat dinonaktifkan dengan menggunakan opsi pengompilasi /Zc:static_assert-.
Contoh
Di Visual Studio 2022 versi 17.1 dan yang lebih baru, kode ini sekarang menyebabkan kesalahan:
template<typename T>
void f()
{
static_assert(false, "BOOM!");
}
Untuk memperbaiki masalah ini, buat ekspresi bergantung pada sesuatu. Contohnya:
template<typename>
constexpr bool dependent_false = false;
template<typename T>
void f()
{
static_assert(dependent_false<T>, "BOOM!");
}
Dengan perubahan ini, pengompilasi hanya menghasilkan kesalahan jika templat fungsi f diinstansiasi.
Peningkatan kesesuaian di Visual Studio 2022 versi 17.0
Visual Studio 2022 versi 17.0 berisi peningkatan kesesuaian berikut, perbaikan bug, dan perubahan perilaku dalam pengompilasi Microsoft C/C++.
Peringatan tentang lebar bitfield untuk jenis enumerasi
Ketika mendeklarasikan instans jenis enumerasi sebagai bitfield, lebar bitfield harus mengakomodasi semua kemungkinan nilai enumerasi. Jika tidak, pengompilasi mengeluarkan pesan diagnostik. Pertimbangkan contoh ini: Pertimbangkan:
enum class E : unsigned { Zero, One, Two };
struct S {
E e : 1;
};
Seorang programmer mungkin mengharapkan anggota kelas S::e dapat menyimpan salah satu nilai bernama enum secara eksplisit. Mengingat jumlah elemen enumerasi, itu tidak mungkin. Bitfield tidak dapat mencakup rentang nilai E yang disediakan secara eksplisit (secara konseptual, ini adalah domain dari E). Untuk mengatasi kekhawatiran bahwa lebar bitfield tidak cukup besar untuk domain enumerasi, peringatan baru (nonaktif secara default) ditambahkan ke MSVC:
t.cpp(4,5): warning C5249: 'S::e' of type 'E' has named enumerators with values that cannot be represented in the given bit field width of '1'.
E e : 1;
^
t.cpp(1,38): note: see enumerator 'E::Two' with value '2'
enum class E : unsigned { Zero, One, Two };
^
Perilaku pengompilasi ini adalah perubahan pemecahan sumber dan biner yang memengaruhi semua mode /std dan /permissive.
Kesalahan pada perbandingan pointer terurut terhadap nullptr atau 0
Standar C++ secara tidak sengaja mengizinkan perbandingan pointer yang diurutkan terhadap nullptr atau 0. Contohnya:
bool f(int *p)
{
return p >= 0;
}
Kertas WG21 N3478 menghilangkan pengawasan ini. Perubahan ini diimplementasikan dalam MSVC. Ketika contoh dikompilasi dengan menggunakan /permissive- (dan /diagnostics:caret), contoh tersebut memancarkan kesalahan berikut:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
return p >= 0;
^
Perilaku pengompilasi ini adalah perubahan pemecahan sumber dan biner yang memengaruhi kode yang dikompilasi menggunakan /permissive- di semua /std mode.