g ++ referência indefinida para typeinfo

Acabei de encontrar o seguinte erro (e encontrei a solução online, mas ela não está presente no Stack Overflow):

(.gnu.linkonce. [stuff]): referência indefinida a [method] [arquivo object] :(. gnu.linkonce. [stuff]): referência indefinida a `typeinfo para [classname] ‘

Por que alguém pode obter um desses erros de vinculador de “referência indefinida para o tipo”?

(Pontos de bônus se você puder explicar o que está acontecendo nos bastidores.)

Um possível motivo é porque você está declarando uma function virtual sem defini-la.

Quando você o declara sem defini-lo na mesma unidade de compilation, você está indicando que ele está definido em outro lugar – isso significa que a fase de vinculação tentará encontrá-lo em uma das outras unidades de compilation (ou bibliotecas).

Um exemplo de definir a function virtual é:

 virtual void fn() { /* insert code here */ } 

Nesse caso, você está anexando uma definição à declaração, o que significa que o vinculador não precisa resolvê-la posteriormente.

A linha

 virtual void fn(); 

declara fn() sem defini-lo e causará a mensagem de erro que você perguntou.

É muito parecido com o código:

 extern int i; int *pi = &i; 

que afirma que o inteiro i é declarado em outra unidade de compilation que deve ser resolvida no momento do link (caso contrário, pi não pode ser configurado para seu endereço).

Isso também pode acontecer quando você mistura o -fno-rtti e -frtti . Então você precisa garantir que qualquer class, que type_info é acessada no código -frtti , tenha seu método key compilado com -frtti . Esse access pode acontecer quando você cria um object da class, usa dynamic_cast etc.

[ fonte ]

Isso ocorre quando funções virtuais declaradas (não-puras) são corpos ausentes. Na sua definição de class, algo como:

 virtual void foo(); 

Deve ser definido (inline ou em um arquivo de origem vinculado):

 virtual void foo() {} 

Ou declarado virtual puro:

 virtual void foo() = 0; 

Citando o manual do gcc :

Para classs polimórficas (classs com funções virtuais), o object type_info é escrito junto com o vtable […] Para todos os outros tipos, nós escrevemos o object type_info quando ele é usado: ao aplicar `typeid ‘a uma expressão, lançando um object ou referindo-se a um tipo em uma cláusula catch ou especificação de exceção.

E um pouco mais cedo na mesma página:

Se a class declarar qualquer function virtual não inline, não-pura, a primeira é escolhida como o “método chave” para a class, e a vtable é emitida somente na unidade de tradução onde o método chave é definido.

Então, esse erro acontece quando o “método chave” não tem sua definição, como outras respostas já mencionadas.

Se você estiver ligando um .so para outro, mais uma possibilidade é compilar com “-visualização = oculto” no gcc ou g ++. Se ambos os arquivos .so foram construídos com “-visibilidade = oculto” e o método chave não está no mesmo .assim como outras implementações da function virtual, o último não verá a vtable ou o tipoinfo do primeiro. Para o vinculador, isso parece uma function virtual não implementada (como nas respostas de paxdiablo e cdleary).

Neste caso, você deve abrir uma exceção para a visibilidade da class base com

 __attribute__ ((visibility("default"))) 

na declaração de class. Por exemplo,

 class __attribute__ ((visibility("default"))) boom{ virtual void stick(); } 

Outra solução, é claro, é não usar “-visibilidade = oculto”. Isso complica as coisas para o compilador e o vinculador, possivelmente em detrimento do desempenho do código.

As respostas anteriores estão corretas, mas esse erro também pode ser causado pela tentativa de usar o typeid em um object de uma class que não possui funções virtuais. C ++ O RTTI requer uma vtable, portanto, as classs nas quais você deseja executar a identificação de tipo requerem pelo menos uma function virtual.

Se você quiser que as informações de tipo funcionem em uma class para a qual você não deseja realmente nenhuma function virtual, torne o destruidor virtual.

Possíveis soluções para código que lidam com bibliotecas RTTI e não RTTI:

a) Recompile tudo com -frtti ou -fno-rtti
b) Se a) não for possível para você, tente o seguinte:

Suponha que libfoo é construído sem RTTI. Seu código usa o libfoo e compila com o RTTI. Se você usa uma class (Foo) na libfoo que possui virtuals, é provável que você encontre um erro de tempo de link que diz: missing typeinfo para a class Foo.

Defina outra class (por exemplo, FooAdapter) que não tenha virtual e encaminhe chamadas para o Foo que você usa.

Compile o FooAdapter em uma pequena biblioteca estática que não use o RTTI e dependa apenas dos símbolos libfoo. Forneça um header para ele e use isso em seu código (que usa o RTTI). Como o FooAdapter não tem nenhuma function virtual, ele não terá nenhum tipo de informação e você poderá vincular seu binário. Se você usa muitas classs diferentes da libfoo, esta solução pode não ser conveniente, mas é um começo.

Eu passei apenas algumas horas com este erro, e enquanto as outras respostas aqui me ajudaram a entender o que estava acontecendo, elas não corrigiram meu problema específico.

Eu estou trabalhando em um projeto que compila usando clang++ e g++ . Eu não estava tendo problemas de vinculação usando o clang++ , mas estava obtendo a undefined reference to 'typeinfo for erro com g++ .

O ponto importante: Vinculando a ordem MATTERS com g++ . Se você listar as bibliotecas que deseja vincular em uma ordem incorreta, poderá obter o erro typeinfo .

Veja esta pergunta SO para mais detalhes sobre como vincular a ordem ao gcc / g++ .

De maneira semelhante à discussão RTTI, NO-RTTI acima, esse problema também pode ocorrer se você usar dynamic_cast e falhar ao include o código do object que contém a implementação da class.

Eu corri para esse problema construindo o Cygwin e depois portando o código para o Linux. Os arquivos make, a estrutura de diretórios e até mesmo as versões gcc (4.8.2) eram idênticas em ambos os casos, mas o código era vinculado e operado corretamente no Cygwin, mas falhava em vincular no Linux. O Red Hat Cygwin aparentemente fez modificações no compilador / linker que evitam o requisito de vinculação de código de object.

A mensagem de erro do vinculador do Linux me direcionou corretamente para a linha dynamic_cast, mas mensagens anteriores neste fórum me fizeram procurar implementações de function ausentes, em vez do problema real: código de object ausente. Minha solução alternativa era replace uma function de tipo virtual na class base e derivada, por exemplo, virtual int isSpecialType (), em vez de usar dynamic_cast. Essa técnica evita o requisito de vincular o código de implementação de object apenas para que o dynamic_cast funcione corretamente.

Na class base (uma class base abstrata) você declara um destruidor virtual e como você não pode declarar um destruidor como uma function virtual pura, você deve defini-lo aqui mesmo na class abstrata, apenas uma definição fictícia como virtual ~ base ( ) {} fará, ou em qualquer class derivada.

Se você não fizer isso, você acabará em um “símbolo indefinido” no momento do link. Desde VMT tem uma input para todas as funções virtuais puras com um NULL correspondente, uma vez que atualiza a tabela, dependendo da implementação na class derivada. Mas, para as funções não-puras, mas virtuais, ele precisa da definição no tempo do link para poder atualizar a tabela do VMT.

Use c ++ filt para desmanchar o símbolo. Como $ c ++ filt _ZTIN10storageapi8BaseHostE irá mostrar algo como “typeinfo para storageapi :: BaseHost”.

Eu tenho muitos desses erros agora. O que aconteceu é que eu divido uma class de arquivo de header apenas em um arquivo de header e um arquivo cpp. No entanto, não atualizei meu sistema de compilation, portanto, o arquivo cpp não foi compilado. Entre simplesmente ter referências indefinidas para as funções declaradas no header, mas não implementadas, recebi muitos desses erros de tipo.

A solução foi executar novamente o sistema de compilation para compilar e vincular o novo arquivo cpp.

No meu caso, eu usei uma biblioteca de terceiros com arquivos de header e, portanto, arquivo. Eu subclass uma class e erro de link como este ocorreu quando eu tento instanciar minha subclass.

como mencionado por @sergiy, sabendo que poderia ser o problema de ‘rtti’, eu consegui contornar isso colocando a implementação do construtor em arquivo .cpp separado e aplicar sinalizadores de compilation ‘-fno-rtti’ no arquivo . isso funciona bem.

Como ainda não estou muito claro sobre o interno deste erro de link, não tenho certeza se a minha solução é geral. no entanto, eu acho que vale a pena tentar antes de tentar o caminho do adaptador como mencionado por @ francis. e, claro, se todos os códigos-fonte estiverem disponíveis (não no meu caso), é melhor recompilar com ‘-frtti’, se possível.

mais uma coisa, se você optar por tentar a minha solução, tente tornar o arquivo separado o mais simples possível, e não use alguns resources sofisticados do C ++. ter atenção especial em impulsionar coisas relacionadas, pois muito disso depende do rtti.

Eu encontro uma situação que é rara, mas isso pode ajudar outros amigos em situação semelhante. Eu tenho que trabalhar em um sistema mais antigo com o gcc 4.4.7. Eu tenho que compilar o código com c + + 11 ou acima de suporte, então eu construo a versão mais recente do gcc 5.3.0. Ao criar meu código e vincular às dependencies se a dependência for criada com o compilador mais antigo, obtive um erro de ‘referência indefinida’ mesmo quando defini claramente o caminho de vinculação com -L / path / to / lib -llibname. Alguns pacotes como boost e projetos criados com o cmake geralmente tendem a usar o compilador mais antigo, e geralmente causam esses problemas. Você precisa percorrer um longo caminho para garantir que eles usem o compilador mais recente.

Eu tenho o mesmo erro quando minha interface (com todas as funções virtuais puras) precisou de mais uma function e eu esqueci de “nulo”.

eu tinha

class ICommProvider { public: /** * @brief If connection is established, it sends the message into the server. * @param[in] msg - message to be send * @return 0 if success, error otherwise */ virtual int vaSend(const std::string &msg) = 0; /** * @brief If connection is established, it is waiting will server response back. * @param[out] msg is the message received from server * @return 0 if success, error otherwise */ virtual int vaReceive(std::string &msg) = 0; virtual int vaSendRaw(const char *buff, int bufflen) = 0; virtual int vaReceiveRaw(char *buff, int bufflen) = 0; /** * @bief Closes current connection (if needed) after serving * @return 0 if success, error otherwise */ virtual int vaClose(); };

O último vaClose não é virtual, então, compilado não sabia onde obter implementação para ele e, assim, ficava confuso. minha mensagem foi:

… TCPClient.o :(. Rodata + 0x38): referência indefinida para `typeinfo para ICommProvider ‘

Mudança simples de

 virtual int vaClose(); 

para

 virtual int vaClose() = 0; 

resolveu o problema. espero que ajude