“警告:使用GCC和GDB(CodeBlocks)找不到值为XXX值的虚拟表的链接器符号”

时间:2012-01-01 20:45:35

标签: c++ gcc gdb virtual-functions

我收到一个运行时错误(“无法写入内存”),在通过调试器检查后,会导致警告。

标题如下:

componente.h:

#ifndef COMPONENTE_H
#define COMPONENTE_H

using namespace std;

class componente
{
        int num_piezas;
        int codigo;
        char* proovedor;
    public:
        componente();
        componente(int a, int b, const char* c);
        virtual ~componente();
        virtual void print();

};

#endif // COMPONENTE_H

complement.h实施

#include "Componente.h"
#include <string.h>
#include <iostream>

componente::componente()
{
    num_piezas = 0;
    codigo = 0;
    strcpy(proovedor, "");
    //ctor
}

componente::componente(int a = 0, int b = 0, const char* c = "")
{
    num_piezas = a;
    codigo = b;
    strcpy(proovedor, "");
}

componente::~componente()
{
    delete proovedor;//dtor
}

void componente::print()
{
    cout << "Proovedor: " << proovedor << endl;
    cout << "Piezas:    " << num_piezas << endl;
    cout << "Codigo:    " << codigo << endl;
}

teclado.h

#ifndef TECLADO_H
#define TECLADO_H

#include "Componente.h"


class teclado : public componente
{
        int teclas;
    public:
        teclado();
        teclado(int a, int b, int c, char* d);
        virtual ~teclado();
        void print();


};

#endif // TECLADO_H

teclado.h实施

#include "teclado.h"
#include <iostream>

teclado::teclado() : componente()
{
    teclas = 0;//ctor
}

teclado::~teclado()
{
    teclas = 0;//dtor
}

teclado::teclado(int a = 0, int b = 0, int c = 0, char* d = "") : componente(a,b,d)
{
    teclas = c;
}

void teclado::print()
{
    cout << "Teclas: " << teclas << endl;
}

我得到运行时错误的主要方法如下:

#include <iostream>
#include "teclado.h"

using namespace std;

int main()
{
    componente a; // here I have the breakpoint where I check this warning
    a.print();
    return 0;
}

但是,如果不创建“componente”对象,我创建了一个“teclado”对象,我没有得到运行时错误。我仍然在调试期间收到警告,但程序的行为符合预期:

#include <iostream>
#include "teclado.h"

using namespace std;

int main()
{
    teclado a;
    a.print();
    return 0;
}

这会返回“Teclas = 0”加上“按任意键......”的事情。

你知道链接器为什么会遇到麻烦吗?当我调用虚函数时,但在构造之前,它不显示。

2 个答案:

答案 0 :(得分:10)

我可以看到两个错误:

strcpy(proovedor, "");  // No memory has been allocated to `proovedor` and
                        // it is uninitialised.

由于它未被初始化,这可能会覆盖进程内存中的任何位置,因此可能会破坏虚拟表。

您可以将其更改为(在两个构造函数中):

proovedor = strdup("");

析构函数在delete上使用了错误的proovedor

delete proovedor; // should be delete[] proovedor

由于这是C ++,您应该考虑使用std::string而不是char*

如果您不更改为std::string,则需要:

  1. 如果您有一个动态分配的成员变量,则实现复制构造函数和赋值运算符,因为默认版本不正确
  2. 使复制构造函数和赋值运算符为私有,使其无法使用。

答案 1 :(得分:1)

同一消息的另一个来源是gdb可能会被尚未初始化的变量搞糊涂。 (这回答了问题标题,但不是OP的问题,因为网络搜索让我在这里寻找答案。)

当然,你不应该有未初始化的变量,但在我的情况下,gdb尝试在声明/初始化之前显示函数局部变量。

今天我逐步介绍了另一个开发人员的gtest案例,每次调试器停止时,此消息都会被转储到输出。在这种情况下,有问题的变量在〜第245行声明,但是函数在第202行开始。每次我在这些行之间停止调试器时,我收到了消息。

我通过将变量声明移到函数顶部来处理这个问题。

供参考,我在QtCreator 4.1.0中使用gdb版本7.11.1进行测试,并使用g ++版本5.4.1进行编译