Nejnovější změny ve Visual C++
Při upgradu na novou verzi kompilátoru jazyka Visual C++ může dojít ke kompilačním nebo běhovým chybám v kódu, který se dříve kompiloval a běžel správně.Změny v nové verzi, které způsobí takovým problémům se označují jako nejnovější změny, a obvykle budete vyžadované změny provedené v standardní jazyk C++, funkce signatury nebo rozložení objektů v paměti.
I když je zaručeno, že se rozložení objektů typu „obyčejná stará data“ POD (plain old data) a rozhraní modelu COM nebudou mezi verzemi měnit, mohou se v jazyce Visual C++ měnit jiné druhy rozložení objektů, například ve scénářích, které zahrnují dědičnost nebo vytváření instancí šablon.
Aby se zabránilo chybám za běhu, které by bylo obtížné najít a diagnostikovat, doporučujeme vám nikdy nevytvářet statická propojení na binární soubory, které byly zkompilovány pomocí jiných verzí kompilátoru.Když upgradujete projekt EXE nebo DLL, nezapomeňte také provést upgrade knihoven, na které odkazuje.Pokud používáte typy CRT (C Runtime) nebo STL (Standard Template Library), nepředávejte je mezi binárními soubory (včetně knihoven DLL), které byly zkompilovány pomocí jiných verzí kompilátoru.Další informace naleznete v tématu Možné chyby při předávání objektů CRT přes hranice knihovny DLL.
Dále doporučujeme nikdy nepsat kód závislý na konkrétním rozložení pro objekt, který není rozhraním modelu COM nebo objektem POD.Pokud takový kód napíšete, musíte zajistit, aby po upgradu fungoval.Další informace naleznete v tématu Přenositelnost u rozhraní ABI (moderní verze jazyka C++).
Zbývající část tohoto článku popisuje konkrétní nejnovějších změn v Visual C++ v sadě Visual Studio 2013.
Kompilátor Visual C++
Konečné klíčové slovo nyní v případech, kdy by bylo dříve zkompilováno, vygeneruje chybu nevyřešeného symbolu:
struct S1 { virtual void f() = 0; }; struct S2 final : public S1 { virtual void f(); }; int main(S2 *p) { p->f(); }
V dřívějších verzích nebyla chyba vyvolána, protože volání bylo virtuální volání; program by však spadl za běhu.Nyní je přiřazena chyba linkeru, protože třída je nyní označena jako konečná.V tomto příkladu chcete-li opravit chyby, by propojení proti obj., který obsahuje definici S2::f.
Při použití přítele funkcí v obory názvů, je třeba znovu deklarovat funkci přítele dříve, než je na něj odkazovat nebo obdržíte chybu, protože kompilátor nyní odpovídá ISO C++ Standard.Toto se například již nezkompiluje:
namespace NS { class C { void func(int); friend void func(C* const) {} }; void C::func(int) { NS::func(this); // error } }
Chcete-li tento kód opravit, deklarujte funkci přítele:
namespace NS { class C { void func(int); friend void func(C* const) {} }; void func(C* const); // conforming fix void C::func(int) { NS::func(this); } }
C++ Standard nepovoluje explicitní dosažené v třídě.Visual C++ to sice v některých případech umožňuje, ale v případech, jako je následující příklad, je nyní generována chyba, protože kompilátor nezahrne druhou funkci jako specializaci té první.
template <int N> class S { public: template void f(T& val); template <> void f(char val); }; template class S<1>;
Chcete-li tento kód opravit, upravte druhou funkci:
template <> void f(char& val);
Visual C++ se již nepokouší zdvojit dvě funkce v následujícím příkladu a nyní generuje chybu:
template<typename T> void Func(T* t = nullptr); template<typename T> void Func(...); int main() { Func<int>(); // error }
Chcete-li tento kód opravit, upřesněte volání:
template<typename T> void Func(T* t = nullptr); template<typename T> void Func(...); int main() { Func<int>(nullptr); // ok }
Před provedením kompilátor kompatibilní s ISO C ++ 11, by mít následující kód zkompilován a způsobilo x přeložit na typ int:
auto x = {0}; int y = x;
Tento kód je nyní přeloží x na typ std::initializer_list<int> a způsobí chybu na dalším řádku, který se pokusí přiřadit x k zadání int.(Neexistuje žádný převod ve výchozím nastavení.) Chcete-li opravit tento kód, použijte int k nahrazení auto:
int x = {0}; int y = x;
Inicializace agregace již není povolena, když typ pravé hodnoty neodpovídá typu levé hodnoty, která je inicializována, a dojde k vyvolání chyby. Důvodem je, že standard ISO C++11 vyžaduje jednotnou inicializaci, aby pracoval bez zužujících převodů.Pokud byla dříve konverze zúžení k dispozici, namísto chyby se zobrazilo varování C4242.
int i = 0; char c = {i}; // error
Chcete-li tento kód opravit, přidejte explicitní zužující převod:
int i = 0; char c = {static_cast<char>(i)};
Následující inicializace již není povolena:
void *p = {{0}};
Chcete-li tento kód opravit, použijte některou z těchto forem:
void *p = 0; // or void *p = {0};
Vyhledání názvu byl změněn. Následující kód je vyřešen jinak v Visual C++ v sadě Visual Studio 2012 a Visual C++ v sadě Visual Studio 2013:
enum class E1 {a}; enum class E2 {b}; int main() { typedef E2 E1; E1::b; }
V Visual C++ v sadě Visual Studio 2012, E1 ve výrazu E1::b přeložit na ::E1 v globálním oboru.V Visual C++ v sadě Visual Studio 2013, E1 ve výrazu E1::b přeloží na typedef E2 v definici main() a má typ ::E2.
Rozložení objektu se změnila. Na platformě x 64 se může v porovnání z předchozími verzemi změnit rozložení objektů třídy.Pokud má virtuální funkci, ale neobsahuje základní třídu, která obsahuje virtuální funkci, objektový model kompilátoru vloží ukazatel na tabulku virtuálních funkcí za rozložení datových členů.To znamená, že rozložení nemusí být ve všech případech optimální.V předchozích verzích optimalizace pro platformu x 64 by se pokusily zlepšit rozložení pro vás, ale protože se nepodařilo správně fungovat v situacích složitější kód, byla odebrána v Visual C++ v sadě Visual Studio 2013.Podívejte se například na tento kód:
__declspec(align(16)) struct S1 { }; struct S2 { virtual ~S2(); void *p; S1 s; };
V Visual C++ v sadě Visual Studio 2013, výsledek sizeof(S2) na platformě x 64 je 48, ale v předchozích verzích vyhodnocen 32.Chcete-li to výsledkem vyhodnocení 32 ve Visual C++ v sadě Visual Studio 2013 pro platformu x 64 přidat fiktivní základní třídu, která obsahuje virtuální funkce:
__declspec(align(16)) struct S1 { }; struct dummy { virtual ~dummy() {} }; struct S2 : public dummy { virtual ~S2(); void *p; S1 s; };
K vyhledání místa ve vašem kódu, který dřívější verze by jste se pokusili optimalizovat použijte kompilátoru z této verze spolu s /W3 Možnosti kompilátoru a zapne 4370 upozornění.Příklad:
#pragma warning(default:4370) __declspec(align(16)) struct S1 { }; struct S2 { virtual ~S2(); void *p; S1 s; };
V jazyce Visual C++ kompilátoru před Visual C++ v sadě Visual Studio 2013, tento kód výstupy tuto zprávu:
warning C4370: 'S2' : layout of class has changed from a previous version of the compiler due to better packing
V kompilátoru pro x86 existuje má stejný problém s optimalizací rozložení ve všech verzích Visual C++.Pokud je například tento kód je zkompilován pro platformu x86:
struct S { virtual ~S(); int i; double d; };
Výsledek sizeof(S) je 24.Může však být snížena na hodnotu 16, pokud použijete zástupné řešení uvedené výše pro platformu x64:
struct dummy { virtual ~dummy() {} }; struct S : public dummy { virtual ~S(); int i; double d; };
Knihovny jazyka Visual C++
Standardní šablona knihovny
Pokud byte chtěli povolit nové optimalizace a kontroly ladění, implementace standardní knihovny C++ záměrně neumožňuje binární kompatibilitu mezi verzemi.Proto při použití standardní knihovny C++ nelze objektové soubory a statické knihovny, které jsou kompilovány pomocí různých verzí, směšovat v jednom binárním souboru (EXE nebo DLL) a objekty standardní knihovny C++ nelze předávat mezi binárními soubory, které jsou kompilovány pomocí různých verzí.Takovéto směšování objektů vyvolává chyby linkeru týkající se neshod _MSC_VER.(_MSC_VER je makra, které obsahuje hlavní verze kompilátoru – například 1800 pro Visual C++ v sadě Visual Studio 2013.) Tuto kontrolu nelze zjistit DLL míšení a nelze zjistit míšení, které jsou zapojeny Visual C++ 2008 nebo dřívější.
Visual C++ v sadě Visual Studio 2013 zjistí neshody v makru _ITERATOR_DEBUG_LEVEL, které bylo implementováno ve Visual C++ 2010, a neshody RuntimeLibrary.Tyto dojít při – možnosti kompilátoru /MT (statické vydání), /MTd (statické ladění), /MD (dynamické vydání), a /MDd (dynamické ladění) jsou mixed.Další informace naleznete v tématu nejnovější změny v sadě Visual C++ 2012.
Pokud váš kód potvrzuje předchozí simulované aliasy šablon ve vydání, je třeba je změnit.Můžete například místo z allocator_traits<A>::rebind_alloc<U>::other, nyní máte chcete, aby byly allocator_traits<A>::rebind_alloc<U>.I když ratio_add<R1, R2>::type již není nutné a My nyní doporučujeme řeknete ratio_add<R1, R2>, Bývalé stále zkompiluje protože ratio<N, D> musí mít definice typu "typ" pro sníženou poměr, který bude stejného typu, pokud je již snižuje.
Je nutné použít #include <algorithm> Při volání std::min() nebo std::max().
Pokud váš stávající kód používá simulovaný obor výčtů předchozí verze – tradiční výčty bez oboru zabalené v oborech názvů – je třeba je změnit.Například pokud jste vytvořili odkaz na typ std::future_status::future_status, nyní máte chcete, aby byly std::future_status.Většinu kódu je však dotčeny – například std::future_status::ready stále kompiluje.
explicit operator bool() je přísnější než operator unspecified-bool-type().explicit operator bool() umožňuje explicitní převody k bool– například uděleno shared_ptr<X> sp, obě static_cast<bool>(sp) a bool b(sp) jsou platné – a testování logickou hodnotu "kontextové převody" na bool– například if (sp), !sp, sp && whatever.Však explicit operator bool() zakazuje implicitní převod bool, takže nemůže řeknete bool b = sp; a zadané bool Návratový typ, nelze řeknete return sp.
Nyní, když jsou implementovány skutečné variadické šablony, příkaz _VARIADIC_MAX a související makra nemají žádný vliv. Pokud stále definujete _VARIADIC_MAX, je to prostě ignorováno. Je-li potvrzen náš nástroj maker určený k podpoře simulovaných variadic šablon jiným způsobem, je nutné změnit váš kód.
Kromě běžných klíčových slov záhlaví STL nyní zakazují makroizaci kontextově závislých klíčových slov "override" a "final".
reference_wrapper/ref()/cref() nyní nezakazuje vazby ke dočasné objekty.
<random> Nyní přísně používá jeho kompilaci předpoklady.
Různé typové vlastnosti STL mají předpoklad „T musí být dokončený typ“.Ačkoli je kompilátor nyní vynucuje přísněji, nemusí je vynutit ve všech situacích.(Protože porušení předběžných podmínek STL spustí nedefinované chování, standard nezaručuje vynucení.)
STL nepodporuje /clr:oldSyntax.
C ++ 11 specifikacecommon_type <> obsahovalo neočekávané a nežádoucí důsledky; obzvláště dává common_type<int, int>::type vrátit int&&.Proto Visual C++ implementuje navrhovaný řešení problému knihovny pracovní skupina 2141, což usnadňuje common_type<int, int>::type vrátit int.
Jako vedlejší účinek této změny, v případě identity přestane fungovat (common_type<T> nemá vždy za následek typu T).To odpovídá navrženému řešení, ale dojde k porušení jakéhokoli kódu, který spoléhal na předchozí chování.
Pokud budete potřebovat výšku typ identity, nepoužívejte nestandardní std::identity který je definován v <type_traits> vzhledem k tomu, že nebude fungovat pro < void >.Místo toho implementujte vlastní typovou vlastnost identity tak, aby vyhovovala vašim potřebám.Tady je příklad:
template <typename T> struct Identity { typedef T type; };
Rozhraní MFC a knihovna ATL
Knihovna MFC MBCS již není zahrnuta v aplikaci Visual Studio, protože kódování Unicode je oblíbené a používání znakové sady MBCS je výrazně omezeno.Tato změna také udržuje MFC lépe zarovnané s Windows SDK, protože mnoho ovládacích prvků a zpráv má pouze kódování Unicode.Nicméně pokud musí pokračovat v knihovně MFC MBCS, můžete ji stáhnout z MSDN Download Center.Distribuovatelný balíček Visual C++ stále zahrnuje i tuto knihovnu.
Usnadnění pro pásu karet MFC je změněno. Namísto jednoúrovňového architektura je nyní hierarchickou architekturu. Můžete nadále používat staré chování voláním CRibbonBar::EnableSingleLevelAccessibilityMode().
Metoda CDatabase::GetConnect je odebrán. Chcete-li zvýšit zabezpečení, jsou nyní uloženy připojovací řetězec zašifrována a je dešifrovat pouze v případě potřeby; nemůže být vrácen jako prostý text. Řetězec lze získat pomocí CDatabase::Dump metody.
Podpis CWnd::OnPowerBroadcast je změněno. Podpis tohoto popisovače zprávy se změní na LPARAM jako druhý parametr.
Signatury se změní na zohlednit obslužné rutiny zpráv. Seznamy parametrů u následujících funkcí se změnily a používají nově přidané popisovače zpráv ON_WM_ *:
CWnd::OnDisplayChange změněno tak, aby (UINT, int, int) místo (WPARAM, LPARAM) tak, aby nová ON_WM_DISPLAYCHANGE makra lze použít v mapě zpráv.
CFrameWnd::OnDDEInitiate změněno tak, aby (CWnd*, UINT, UNIT) místo (WPARAM, LPARAM) tak, aby nová ON_WM_DDE_INITIATE makra lze použít v mapě zpráv.
CFrameWnd::OnDDEExecute změněno tak, aby (CWnd*, HANDLE) místo (WPARAM, LPARAM) tak, aby nová ON_WM_DDE_EXECUTE makra lze použít v mapě zpráv.
CFrameWnd::OnDDETerminate změněno tak, aby (CWnd*) jako parametr místo (WPARAM, LPARAM) tak, aby nová ON_WM_DDE_TERMINATE makra lze použít v mapě zpráv.
CMFCMaskedEdit::OnCut změnit na žádné parametry místo (WPARAM, LPARAM) tak, aby nová ON_WM_CUT makra lze použít v mapě zpráv.
CMFCMaskedEdit::OnClear změnit na žádné parametry místo (WPARAM, LPARAM) tak, aby nová ON_WM_CLEAR makra lze použít v mapě zpráv.
CMFCMaskedEdit::OnPaste změnit na žádné parametry místo (WPARAM, LPARAM) tak, aby nová ON_WM_PASTE makra lze použít v mapě zpráv.
#ifdefs v souborech MFC záhlaví budou odebrány. Mnoho #ifdefs v hlavičce MFC soubory související s Nepodporovaná verze systému Windows (WINVER < 0x0501) budou odebrány.
Knihovna ATL DLL (atl120.dll) je odebrán. Knihovna ATL je nyní poskytována jako záhlaví a statická knihovna (atls.lib).
Atlsd.lib, atlsn.lib a atlsnd.lib budou odebrány. Knihovna Atls.lib již nemá závislosti na znakové sadě ani kód specifický pro ladění/vydání.Protože princip funkce je stejný pro Unicode/ANSI i ladění/vydání, je vyžadována pouze jedna verze knihovny.
Trasovací nástroj ATL nebo MFC je odebrán společně s knihovnou ATL DLL a mechanismus trasování je zjednodušen.CTraceCategory Konstruktor nyní přijímá jeden parametr (název kategorie) a TRACE makra volání CRT ladění funkce generování sestav.