Partilhar via


Alterações significativas do Visual C++

Ao fazer a atualização para uma nova versão do compilador do Visual C++, você pode encontrar erros de compilação e/ou de tempo de execução no código que foi compilado anteriormente e executado corretamente.As alterações na nova versão que causam tais problemas são conhecidas como alterações significativas e, normalmente, são exigidas pelas modificações no padrão da linguagem C++, nas assinaturas de função ou no layout de objetos na memória.

No Visual C++, embora haja garantia de que o layout do objeto POD (dados antigos simples) e as interfaces COM não se corrompam de versão para versão, outros tipos de layout de objeto (por exemplo, em cenários que envolvem herança ou instanciação de modelo) estão sujeitos à alteração.

Para evitar os erros de tempo de execução que são difíceis de detectar e diagnosticar, é recomendável nunca vincular estaticamente a binários que foram compilados usando diferentes versões do compilador.Além disso, ao fazer atualização de um projeto EXE ou DLL, assegure-se de atualizar as bibliotecas às quais ele se vincula.Se estiver usando tipos CRT (Tempo de execução de C) ou STL (Biblioteca de Modelos Padrão), não os passe entre binários (incluindo DLLs) que foram compilados usando diferentes versões do compilador.Para obter mais informações, consulte Erros em potencial passando por objetos CRT em limites de DLL.

Ainda é recomendável nunca escrever código que dependa de um determinado layout de um objeto que não seja uma interface COM ou um objeto POD.Se você escrever tal código, será preciso garantir que ele funcione após a atualização.Para obter mais informações, consulte Portabilidade em limites ABI (C++ moderno).

O restante deste artigo descreve as alterações significativas específicas feitas no Visual C++ no Visual Studio 2013.

Compilador do Visual C++

  • A palavra-chave final agora gera um erro de símbolo não resolvido onde ele foi compilado anteriormente:

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

    Nas versões anteriores, um erro não era emitido porque a chamada era virtual; no entanto, podia haver pane do programa no tempo de execução.Agora, um erro de vinculador é emitido porque a classe é conhecida como final.Neste exemplo, para corrigir o erro, você faria um vínculo com o objeto que contém a definição de S2::f.

  • Ao usar funções friend em namespaces, você deve declarar novamente a função friend antes de fazer referência a ela ou um erro será obtido, pois o compilador agora está de acordo com o ISO C++Standard.Por exemplo, esse código não compila mais:

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

    Para corrigir esse código, declare a função friend:

    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); 
        }
    }
    
  • O C++ Standard não permite a especialização explícita em uma classe.Embora o Visual C++ permita isso em alguns casos, mas em casos como no exemplo a seguir, um erro será gerado porque o compilador não considera a segunda função como sendo uma especialização da primeira.

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

    Para corrigir esse código, modifique a segunda função:

    template <> void f(char& val);
    
  • O Visual C++ não tenta mais diferenciar as duas funções no exemplo a seguir e agora emite um erro:

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

    Para corrigir esse código, esclareça a chamada:

    template<typename T> void Func(T* t = nullptr); 
    template<typename T> void Func(...); 
    
    int main() { 
        Func<int>(nullptr); // ok
    } 
    
  • Antes de tornar o compilador compatível com o ISO C++11, o seguinte código foi compilado e fez com que x fosse resolvido para o tipo int:

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

    Esse código agora resolve x para um tipo de std::initializer_list<int> e causa um erro na próxima linha que tenta atribuir x ao tipo int.(Não há nenhuma conversão por padrão.) Para corrigir esse código, use int para substituir auto:

    int x = {0}; 
    
    int y = x; 
    
  • A inicialização de agregação não é mais permitida quando o tipo do valor do lado direito não corresponde ao tipo do valor do lado esquerdo que está sendo inicializado, e um erro é emitido porque o ISO C++11 Standard exige inicialização uniforme para funcionar sem conversões de redução.Antigamente, se uma conversão de redução estivesse disponível, um aviso C4242 seria emitido, e não um erro.

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

    Para corrigir esse código, adicione uma conversão de redução explícita:

    int i = 0;
    char c = {static_cast<char>(i)};
    
  • A seguinte inicialização não é mais permitida:

    void *p = {{0}};
    

    Para corrigir esse código, use qualquer uma destas formas:

    void *p = 0; 
    // or 
    void *p = {0};
    
  • A pesquisa de nome foi alterada. O código a seguir é resolvido de forma diferente no Visual C++ no Visual Studio 2012 e no Visual C++ no Visual Studio 2013:

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

    No Visual C++ no Visual Studio 2012, o E1 na expressão E1::b é resolvido para ::E1 no escopo global.No Visual C++ no Visual Studio 2013, E1 na expressão E1::b é resolvido para a definição typedef E2 em main() e tem o tipo ::E2.

  • O layout do objeto foi alterado. No x64, o layout do objeto de uma classe pode ser alterado em relação às versões anteriores.Se ele tiver uma função virtual, mas não tiver uma classe base que tenha uma função virtual, o modelo de objeto do compilador inserirá um ponteiro em uma tabela de função virtual após o layout do membro de dados.Isso significa que o layout pode não ser ideal em todos os casos.Em versões anteriores, uma otimização para o x64 tentaria melhorar o layout para você, mas como ele falhou ao funcionar corretamente em situações de código complexas, foi removida do Visual C++ no Visual Studio 2013.Por exemplo, pense neste código:

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

    No Visual C++ no Visual Studio 2013, o resultado de sizeof(S2) no x64 é 48, mas em versões anteriores, ele seria avaliado em 32.Para fazer essa avaliação em 32 no Visual C++ no Visual Studio 2013 para x64, adicione uma classe base fictícia que tenha uma função virtual:

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

    Para encontrar locais no seu código que uma versão anterior tentou otimizar, use um compilador dessa versão juntamente com a opção de compilador /W3 e ative o Aviso 4370.Por exemplo:

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

    Nos compiladores do Visual C++ antes do Visual C++ no Visual Studio 2013, esse código gerava esta mensagem:

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

    O compilador x86 tem o mesmo problema de layout de qualidade inferior em todas as versões do Visual C++.Por exemplo, se este código foi compilado por x86:

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

    O resultado de sizeof(S) será 24.No entanto, isso pode ser reduzido para 16 se você usar a solução alternativa que acabou de ser mencionada para x64:

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

Bibliotecas do Visual C++

Biblioteca de Modelos Padrão

Para habilitar novas otimizações e verificações de depuração, a implementação da Biblioteca Padrão do C++ do Visual Studio desfaz intencionalmente a compatibilidade binária de uma versão para a próxima.Desse modo, quando a Biblioteca Padrão do C++ é usada, os arquivos de objeto e as bibliotecas estáticas que são compiladas usando versões diferentes não podem ser combinados em um binário (EXE ou DLL), e os objetos da Biblioteca Padrão do C++ não podem ser passados entre binários que são compilados usando versões diferentes.Tal combinação emite erros de vinculador sobre as incompatibilidades de _MSC_VER.(_MSC_VER é uma macro que contém a versão principal do compilador, por exemplo, 1800 para Visual C++ no Visual Studio 2013.) Essa verificação não detecta combinação DLL e não pode detectar uma combinação que envolva Visual C++ 2008 ou anterior.

O Visual C++ no Visual Studio 2013 detecta incompatibilidades em _ITERATOR_DEBUG_LEVEL, que foi implementado no Visual C++ 2010, bem como incompatibilidades de RuntimeLibrary.Essas incompatibilidades ocorrem quando as opções de compilador /MT (versão estática), /MTd (depuração estática), /MD (versão dinâmica) e /MDd (depuração dinâmica) são combinadas.Para obter mais informações, consulte alterações significativas no Visual C++ 2012.

  • Se seu código reconhecer os modelos de alias simulados da versão anterior, você terá que alterá-lo.Por exemplo, em vez de allocator_traits<A>::rebind_alloc<U>::other, agora você precisa expressar allocator_traits<A>::rebind_alloc<U>.Embora ratio_add<R1, R2>::type agora não seja mais necessário e seja recomendado que você explicite ratio_add<R1, R2>, o antigo ainda será compilado porque é obrigatório que ratio<N, D> tenha um "tipo" typedef para um índice reduzido, que será o mesmo tipo se já tiver sido reduzido.

  • Você deve usar #include <algorithm> ao chamar std::min() ou std::max().

  • Se o seu código existente usa enumerações com escopo simuladas da versão anterior — enumerações sem escopo tradicionais envolvidas em namespaces — será necessário alterá-lo.Por exemplo, se você fez referência ao tipo std::future_status::future_status, agora é preciso expressar std::future_status.No entanto, a maioria dos códigos não é afetada, por exemplo, std::future_status::ready ainda é compilado.

  • explicit operator bool() mais rígida que operator unspecified-bool-type().explicit operator bool() permite conversões explícitas para bool— por exemplo, desde que shared_ptr<X> sp, static_cast<bool>(sp) e bool b(sp) sejam válidos — e "conversões contextuais" testáveis por Booliano para bool— por exemplo, if (sp), !sp, sp && whatever.No entanto, explicit operator bool() proíbe conversões implícitas para bool, portanto, você não pode expressar bool b = sp e, dado um tipo de retorno bool, você não pode expressar return sp.

  • Agora que os modelos reais variadic são implementados, _VARIADIC_MAX e as macros relacionadas não têm efeito. Se você ainda estiver definindo _VARIADIC_MAX, ele será ignorado. Se você reconheceu a maquinaria da macro com suporte a modelos variadic simulados de qualquer outra maneira, será preciso modificar seu código.

  • Além de palavras-chave comuns, os cabeçalhos da STL agora proíbem a criação de macros das palavras-chave "override" e "final" contextuais.

  • reference_wrapper/ref()/cref() agora proíbe a associação a objetos temporários.

  • <random> agora impõe rigidamente suas pré-condições de tempo de compilação.

  • Diversas características de tipo da STL têm a pré-condição "T deve ser um tipo completo".Embora o compilador agora imponha isso de forma mais rígida, essa pré-condição não pode ser imposta em todas as situações.(Como as violações de pré-condição da STL disparam o comportamento indefinido, o Padrão não garante a imposição.)

  • A STL não oferece suporte a /clr:oldSyntax.

  • A especificação C++11 paracommon_type teve consequências inesperadas e indesejadas. Particularmente, ela faz common_type<int, int>::type retornar int&&.Portanto, Visual C++ implementa a Resolução proposta para o grupo de trabalho de bibliotecas, versão 2141, o que faz com que common_type<int, int>::type retorne int.

    Como um efeito colateral dessa alteração, o caso de identidade não funciona mais (common_type<T> sem sempre resulta no tipo T).Isso segue a resolução proposta, mas interrompe qualquer código que depende do comportamento anterior.

    Se você exigir uma característica de tipo de identidade, não use std::identity não padrão que seja definida em <type_traits>, pois ela não funcionará para <void>.Em vez disso, implemente sua própria característica de tipo de identidade para atender às suas necessidades.Veja um exemplo:

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

MFC e ATL

  • A Biblioteca MFC MBCS não está mais incluída no Visual Studio porque o Unicode é muito popular e o uso de MBCS foi significativamente reduzido.Essa alteração também mantém o MFC alinhado de forma mais próxima ao próprio Windows SDK, uma vez que vários dos controles e mensagens novos são somente Unicode.Entretanto, se precisar continuar a usar a biblioteca MFC MBCS, você pode baixar no Centro de download do MSDN.O Pacote Redistribuível do Visual C++ ainda inclui esta biblioteca.

  • Acessibilidade para a faixa de opções do MFC é alterada.  Em vez de uma arquitetura de um nível, há agora uma arquitetura hierárquica. Você ainda pode usar o comportamento antigo chamando CRibbonBar::EnableSingleLevelAccessibilityMode().

  • Método CDatabase é removido. Para melhorar a segurança, a cadeia de conexão agora é armazenada criptografada e é descriptografada somente quando necessário; ele não pode ser retornado como texto sem formatação.  A cadeia de caracteres pode ser obtida usando o CDatabase::Dump método.

  • A assinatura de CWnd::OnPowerBroadcast foi alterada. A assinatura desse manipulador de mensagens foi alterada para obter um LPARAM como o segundo parâmetro.

  • As assinaturas são alteradas para acomodar manipuladores de mensagens. As listas de parâmetros das seguintes funções foram alteradas para usar manipuladores de mensagens ON_WM_* recém-adicionados:

    • CWnd::OnDisplayChange foi alterado para (UINT, int, int) em vez de (WPARAM, LPARAM) para que a nova macro ON_WM_DISPLAYCHANGE possa ser usada no mapa de mensagens.

    • CFrameWnd::OnDDEInitiate foi alterado para (CWnd*, UINT, UNIT) em vez de (WPARAM, LPARAM) para que a nova macro ON_WM_DDE_INITIATE possa ser usada no mapa de mensagens.

    • CFrameWnd::OnDDEExecute foi alterado para (CWnd*, HANDLE) em vez de (WPARAM, LPARAM) para que a nova macro ON_WM_DDE_EXECUTE possa ser usada no mapa de mensagens.

    • CFrameWnd::OnDDETerminate foi alterado para (CWnd*) como o parâmetro em vez de (WPARAM, LPARAM) para que a nova macro ON_WM_DDE_TERMINATE possa ser usada no mapa de mensagens.

    • CMFCMaskedEdit::OnCut foi alterado para "sem parâmetros" em vez de (WPARAM, LPARAM) para que a nova macro ON_WM_CUT possa ser usada no mapa de mensagens.

    • CMFCMaskedEdit::OnClear foi alterado para "sem parâmetros" em vez de (WPARAM, LPARAM) para que a nova macro ON_WM_CLEAR possa ser usada no mapa de mensagens.

    • CMFCMaskedEdit::OnPaste foi alterado para "sem parâmetros" em vez de (WPARAM, LPARAM) para que a nova macro ON_WM_PASTE possa ser usada no mapa de mensagens.

  • #ifdefs nos arquivos de cabeçalho MFC são removidos. Vários #ifdefs nos arquivos de cabeçalho MFC relacionados a versões sem suporte do Windows (WINVER < 0x0501) foram removidos.

  • ATL DLL (atl120.dll) foi removida. A ATL agora é fornecida como cabeçalhos e uma biblioteca estática (atls.lib).

  • Atlsd.lib, atlsn.lib e atlsnd.lib foram removidas. Atls.lib não tem dependências ou código de conjunto de caracteres que seja específico para a depuração/versão.Como ela funciona da mesma forma para Unicode/ANSI e depuração/versão, somente uma versão da biblioteca é necessária.

  • A ferramenta Rastreamento de ATL/MFC foi removida com a ATL DLL e o mecanismo de rastreamento foi simplificado.O construtor CTraceCategory agora usa um parâmetro (o nome da categoria) e as macros TRACE chamam as funções de relatório de depuração de CRT.

Consulte também

Outros recursos

Guia de Introdução ao Visual C++ no Visual Studio 2013