GDB incomplete type when having C++ virtual functi

2019-07-24 06:21发布

问题:

I have just noticed something weird, when I add the "virtual keyword" in my class (any function except the constructor), I can't display the content of my object in GDB. GDB says "incomplete type"

Here is the code :

//////////////// reco.h /////////////

#ifndef RECO_H
#define RECO_H

#include <iostream>
#include <string>

class reco {
    public:
        reco(float weight);
        ~reco(void);

        float getWeight();

    private:
        float weight;
};

#endif

///////////////// reco.cpp /////////////

#include <iostream>
#include <string>

#include "reco.h"

using namespace std;

reco::reco(float weight) {
    weight = weight;
}

reco::~reco(void) {
    cout << "destructor reco" << endl;
}

float reco::getWeight() {
    return weight;
}

////////////// main.cpp /////////////

#include <iostream>
#include <string>

#include "reco.h"

using namespace std;


int main() {
    reco* s = new reco(5.0);
    cout << s->getWeight() << endl;

    delete s;

    return 0;
}

Then with GDB :

gdb main.exe
breakpoint main.cpp:11 <---- (cout)
run
print *s
$1 = { weight = 5 }

And then, if I make one of the functions "virtual", and I retry to print my *s pointer with GDB, it says: "incomplete type"

It looks like there is something happening with the VTABLE, as if the "virtual" keyword was hiding the implementation of my Reco class. I know that the compiler does late binding and then, the VTABLE lookup is done at runtime, but the program is already running while GDB is debugging it, right ?

The "set print vtbl" setting in "on".

If I use ptype s, I get the <incomplete type> message again.

If I examine the address with x/540f80, it says "cannot access memory"

I don't know why just adding this keyword makes my object's type incomplete ?

Thanks a lot for your help !

One last thing that I notice :

WITH VIRTUAL:

 reco.cpp -> g0 and main.cpp -> g = incomplete type
 reco.cpp -> g and main.cpp ->g = ok

WITHOUT VIRTUAL

 reco.cpp -> g0 and main.cpp -> g = ok
 reco.cpp -> g and main.cpp ->g = ok

回答1:

reco.cpp -> g and main.cpp ->g = ok

Assuming by -> g you mean that you compile reco.cpp with the -g flag, yes do that, and don't do this:

g++ -c -g0 reco.cpp

What you've discovered that is that GCC can optimize the amount on debug info it must emit if it knows that you have a key method.

Without virtual, there is no key method, and GCC must emit redundant debug info into every compilation unit. That makes your object files larger (it should have little or no effect on the final executable), but allows you to debug even when only some of your object files are compiled with debug info.