Udostępnij za pośrednictwem


Fundamentalne zmiany w Visual C++

Po uaktualnieniu do nowej wersji kompilatora Visual C++ można napotkać błędy kompilacji i/lub błędy czasu wykonywania w kodzie, który wcześniej kompilował się i uruchamiał poprawnie.Zmiany w nowej wersji, które powodują tych problemów są znane jako istotne zmiany, i zazwyczaj jest wymagana przez modyfikacje standardowy języka C++, sygnatury funkcji lub układu obiektów w pamięci.

W Visual C++, chociaż gwarantuje się niezmienność z wersji na wersję układu obiektu POD (zwykłe stare dane — Plain Old Data) i interfejsów COM, inne rodzaje układu obiektu — na przykład w scenariuszach, które wymagają dziedziczenia lub konkretyzacji szablonu — mogą ulec zmianie.

Aby uniknąć błędów czasu wykonywania, które są trudne do wykrycia i zdiagnozowania, zalecamy, aby nigdy nie łączyć statycznie do plików binarnych, które zostały skompilowane przy użyciu innych wersji kompilatora.Ponadto, gdy uaktualniasz projekt EXE lub DLL, upewnij się, że uaktualniasz również biblioteki, z którymi się on łączy.Jeśli używasz typów CRT (środowisko wykonawcze C Runtime) lub STL (standardowa biblioteka szablonów), nie przekazujesz ich między plikami binarnymi (w tym plikami DLL), które zostały skompilowane przy użyciu innych wersji kompilatora.Aby uzyskać więcej informacji, zobacz Potencjalne przekazywanie błędów obiektów CRT w poprzek granic DLL.

Zalecamy też, aby nigdy nie pisać kodu, który zależy od określonego układu dla obiektu niebędącego interfejsem COM lub obiektem POD.Jeśli jednak piszesz taki kod, upewnij się, że działa po uaktualnieniu.Aby uzyskać więcej informacji, zobacz Przenośność na granicach ABI (Modern C++).

Pozostałych członków w tym artykule opisano zmiany podziału określonego w Visual C++ w programie Visual Studio 2013.

Kompilator Visual C++

  • Słowo kluczowe final teraz generuje błąd nierozwiązanego symbolu tam, gdzie kod wcześniej się kompilował:

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

    We wcześniejszych wersjach, błąd nie był generowany ponieważ wywołanie było wywołaniem wirtualnym; niemniej jednak program ulegał awarii w czasie wykonywania.Teraz zostaje zgłoszony błąd konsolidatora, ponieważ wiadomo, że klasa jest ostateczna.W tym przykładzie, aby naprawić błąd, należy połączyć względem obj., która zawiera definicję S2::f.

  • Przy użyciu funkcji przyjaciela w przestrzeni nazw, należy ponownie zadeklarować funkcji znajomego zanim można odwoływać się do niej lub będzie wyświetlany komunikat o błędzie, ponieważ jest zgodny z ISO C++ Standard kompilator.Na przykład, ten kod się już nie kompiluje:

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

    Aby poprawić ten kod, zadeklaruj funkcję zaprzyjaźnioną:

    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 nie zezwala na jawnego specjalizacji w klasie.Chociaż Visual C++ dopuszcza to w niektórych przypadkach, to w przypadku takim, jak poniższy, błąd jest teraz generowany, ponieważ kompilator nie bierze pod uwagę drugiej funkcji jako specjalizacji pierwszej funkcji.

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

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

    template <> void f(char& val);
    
  • Visual C++ nie próbuje już ujednoznaczniać dwóch funkcji w poniższym przykładzie i teraz powoduje błąd:

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

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

    template<typename T> void Func(T* t = nullptr); 
    template<typename T> void Func(...); 
    
    int main() { 
        Func<int>(nullptr); // ok
    } 
    
  • Przed dokonaniem zgodne z ISO C ++ 11 kompilator, czy ma skompilowany i spowodowało następujący kod x prowadzić do typu int:

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

    Ten kod teraz rozpoznaje x do typu std::initializer_list<int> i powoduje błąd w wierszu, który próbuje przypisać x na typ int.(Nie ma domyślnej konwersji.) Aby rozwiązać ten kod, należy użyć int do zamiany auto:

    int x = {0}; 
    
    int y = x; 
    
  • Inicjowanie agregacji nie jest już dozwolone, gdy typ wartości po prawej stronie nie jest zgodny z typem wartości po lewej stronie, który jest inicjowany, i zgłaszany jest błąd, ponieważ standard ISO C++11 wymaga, aby jednolita inicjalizacja działała bez konwersji zawężających.Wcześniej, jeśli konwersja zawężająca była dostępna, zamiast błędu było generowane ostrzeżenie C4242.

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

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

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

    void *p = {{0}};
    

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

    void *p = 0; 
    // or 
    void *p = {0};
    
  • Nazwa wyszukiwania został zmieniony. Poniższy kod został rozwiązany w inny sposób Visual C++ w programie Visual Studio 2012 i Visual C++ w programie Visual Studio 2013:

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

    W Visual C++ w programie Visual Studio 2012, E1 w wyrażeniu E1::b rozpoznane ::E1 w zakresie globalnym.W Visual C++ w programie Visual Studio 2013, E1 w wyrażeniu E1::b jest rozpoznawana jako typedef E2 definicji w main() i ma typ ::E2.

  • Układ obiektu uległ zmianie. W x64, układ obiektu klasy może się zmienić w porównaniu z poprzednimi wydaniami.Jeśli ma on funkcję wirtualną, ale nie ma klasy podstawowej, która ma funkcję wirtualną, model obiektu kompilatora wstawia wskaźnik do tablicy funkcji wirtualnych po układzie elementu członkowskiego danych.Oznacza to, że układ może nie być optymalny we wszystkich przypadkach.W poprzednich wersjach, optymalizację dla procesorów x 64 może spróbować poprawić układu dla Ciebie, ale ponieważ nie działa prawidłowo w sytuacjach złożony kod, został usunięty z Visual C++ w programie Visual Studio 2013.Na przykład, rozważmy ten kod:

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

    W Visual C++ w programie Visual Studio 2013, wynik sizeof(S2) x 64 jest 48, ale w poprzednich wersjach, oblicza do 32.Aby to prowadzi do 32 w Visual C++ w programie Visual Studio 2013 dla procesorów x 64, Dodaj klasę podstawową zastępcza ma wirtualnego funkcji:

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

    Znalezienie miejsc w kodzie wcześniejsza wersja będzie próbować zoptymalizować, użyj kompilatora z tej wersji razem z /W3 opcję kompilatora i Włącz 4370 ostrzeżenie.Na przykład:

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

    Na kompilatorów języka Visual C++ przed Visual C++ w programie Visual Studio 2013, ten kod wyświetla ten komunikat:

    warning C4370: 'S2' : layout of class has changed from a previous version of the compiler due to better packing
    

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

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

    Wynik sizeof(S) jest 24.Można go jednak zmniejszyć do 16, jeśli użyje się wymienionego wcześniej obejścia dla x64:

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

Biblioteki Visual C++

Standardowa biblioteka szablonów

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

Visual C++ w Visual Studio 2013 wykrywa niezgodności w _ITERATOR_DEBUG_LEVEL, który został wprowadzony w Visual C++ 2010, i niezgodności RuntimeLibrary.Występują one podczas opcje kompilatora /MT (wersja statyczny), /MTd (debugowanie statyczny), /MD (wersja dynamiczne), i /MDd (debugowanie dynamiczne) są wymieszane.Aby uzyskać więcej informacji, zobacz istotne zmiany w programie Visual C++ 2012.

  • Jeśli kod rozpoznaje symulowane szablony aliasów z poprzedniej wersji, trzeba to zmienić.Na przykład, zamiast klasy allocator_traits<A>::rebind_alloc<U>::other, gdy już masz znaczy allocator_traits<A>::rebind_alloc<U>.Chociaż ratio_add<R1, R2>::type nie jest już konieczne, możemy teraz zalecamy, aby powiedzieć, możesz ratio_add<R1, R2>, pierwsza będzie nadal skompilować, ponieważ ratio<N, D> musi mieć element typedef "typ" dla zmniejszonej współczynnika, który będzie tego samego typu, jeśli jest już obniżona.

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

  • Jeśli istniejący kod używa symulowanych typów wyliczeniowych w zakresie z poprzedniego wydania — tradycyjnych typów wyliczeniowych bez zakresu owiniętych w przestrzenie nazw — trzeba to zmienić.Na przykład, jeśli określony typ std::future_status::future_status, gdy już masz znaczy std::future_status.Jednak większość kodu nie wpływa na — na przykład std::future_status::ready nadal kompiluje.

  • explicit operator bool() jest bardziej surowych niż operator unspecified-bool-type().explicit operator bool() zezwala na konwersję jawną w bool— na przykład shared_ptr<X> sp, zarówno static_cast<bool>(sp) i bool b(sp) są prawidłowe — i testować wyrażenie logiczne "kontekstowe konwersję" w bool— na przykład if (sp), !sp, sp && whatever.Jednak explicit operator bool() zabrania konwersje niejawne do bool, dlatego nie można powiedzieć bool b = sp; i danych bool zwracany typ, nie można powiedzieć return sp.

  • Teraz, gdy wdrożono rzeczywiste szablony wariadyczne, _VARIADIC_MAX i powiązane makra nie mają żadnego znaczenia. Jeżeli nadal definiujesz _VARIADIC_MAX, jest to po prostu ignorowane. Jeśli przyjmiesz nasze rozwiązania makr przeznaczone do wspierania symulowanych szablonów wariadycznych w jakikolwiek inny sposób, musisz zmienić kod.

  • Oprócz zwykłych słów kluczowych, nagłówki STL teraz zabraniają tworzenia makropoleceń kontekstowych słów kluczowych „override” i „final”.

  • reference_wrapper/ref()/cref() teraz zabraniać powiązania tymczasowe obiektów.

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

  • Różne cechy typu STL mają warunek wstępny „T musi być typem kompletnym”.Mimo że kompilator wymusza to teraz bardziej restrykcyjnie, nie może go wymusić we wszystkich sytuacjach.(Ponieważ naruszenia warunku wstępnego STL wyzwalają niezdefiniowane zachowanie, Standard nie gwarantuje egzekwowania.)

  • STL nie obsługuje /clr:oldSyntax.

  • W C ++ 11 specyfikacjicommon_type <> mieli skutków nieoczekiwany i niepożądane, a w szczególności może ułatwić common_type<int, int>::type zwrócić int&&.Dlatego implementuje Visual C++ proponowane rozwiązania problemu grupy roboczej Biblioteka 2141, który sprawia, że common_type<int, int>::type zwrócić int.

    Jako po stronie efekt tej zmiany, nie będzie działać w przypadku tożsamości (common_type<T> nie zawsze powoduje typu T).Jest to zgodne z Proponowanym rozwiązaniem, ale unieważnia jakikolwiek kod, który opierał się na poprzednim zachowaniu.

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

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

MFC i ATL

  • Biblioteka MFC MBCS nie jest już częścią Visual Studio, ponieważ Unicode jest bardzo popularny i zastosowanie MBCS jest dużo mniejsze.Ta zmiana podtrzymuje również ściślejszą relację między MFC a Windows SDK. ponieważ wiele nowych kontrolek i komunikatów wymaga Unicode.Jednak kontynuowanie musi przy użyciu biblioteki MFC MBCS, możesz pobrać go z Centrum pobierania MSDN.Pakiet redystrybucyjny Visual C++ wciąż zawiera tę bibliotekę.

  • Ułatwienia dostępu dla wstążki MFC zostało zmienione.  Zamiast architektury jeden poziom jest teraz hierarchiczne architektury. Można nadal używać starego zachowania przez wywołanie metody CRibbonBar::EnableSingleLevelAccessibilityMode().

  • Metoda CDatabase::GetConnect zostanie usunięty. Aby zwiększyć zabezpieczenia, ciąg połączenia jest teraz przechowywany szyfrowane i jest odszyfrowane tylko w razie potrzeby; Nie można zwrócić go jako zwykły tekst.  Ten ciąg można uzyskać przy użyciu CDatabase::Dump metody.

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

  • Podpisy zostaną zmienione na pomieszczenie obsługi wiadomości. Listy parametrów dla poniższych funkcji zostały zmienione, aby używać nowo dodanych programów obsługi komunikatów ON_WM_*:

    • CWnd::OnDisplayChange zmieniła się na (UINT, int, int) zamiast (WPARAM, LPARAM) aby nowy ON_WM_DISPLAYCHANGE makra mogą zostać wykorzystane w planie komunikatu.

    • CFrameWnd::OnDDEInitiate zmieniła się na (CWnd*, UINT, UNIT) zamiast (WPARAM, LPARAM) aby nowy ON_WM_DDE_INITIATE makra mogą zostać wykorzystane w planie komunikatu.

    • CFrameWnd::OnDDEExecute zmieniła się na (CWnd*, HANDLE) zamiast (WPARAM, LPARAM) aby nowy ON_WM_DDE_EXECUTE makra mogą zostać wykorzystane w planie komunikatu.

    • CFrameWnd::OnDDETerminate zmieniła się na (CWnd*) jako parametr zamiast (WPARAM, LPARAM) aby nowy ON_WM_DDE_TERMINATE makra mogą zostać wykorzystane w planie komunikatu.

    • CMFCMaskedEdit::OnCut zmieniła się na nie ma żadnych parametrów, zamiast (WPARAM, LPARAM) aby nowy ON_WM_CUT makra mogą zostać wykorzystane w planie komunikatu.

    • CMFCMaskedEdit::OnClear zmieniła się na nie ma żadnych parametrów, zamiast (WPARAM, LPARAM) aby nowy ON_WM_CLEAR makra mogą zostać wykorzystane w planie komunikatu.

    • CMFCMaskedEdit::OnPaste zmieniła się na nie ma żadnych parametrów, zamiast (WPARAM, LPARAM) aby nowy ON_WM_PASTE makra mogą zostać wykorzystane w planie komunikatu.

  • #ifdefs w plikach MFC nagłówka zostaną usunięte. Wiele #ifdefs w nagłówku MFC pliki związane z nieobsługiwanych wersji systemu Windows (WINVER < 0x0501) zostały usunięte.

  • ATL DLL (atl120.dll) zostanie usunięty. ATL jest obecnie dostarczany jako nagłówki i biblioteka statyczna (atls.lib).

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

  • Narzędzie śledzenia ATL/MFC zostało usunięte wraz z biblioteką ATL DLL, uproszczono mechanizm śledzenia.CTraceCategory Konstruktor teraz przyjmuje jeden parametr (nazwa kategorii) i TRACE makra wywołać debugowania CRT funkcje raportowania.

Zobacz też

Inne zasoby

Wprowadzenie do programu Visual C++ w Visual Studio 2013