[ACCEPTED]-Pure Virtual Method Called-pure-virtual

Accepted answer
Score: 12

The problem appears to be that Director::manageWorker is called 14 in the constructor of workerVariant instances:

Director::manageWorker(baseWorkerClass* worker) {
    workerPtrArray[worker->getThreadID()] = worker;
}

Presumably 13 getThreadID() isn't a pure virtual function or you would 12 have (hopefully!) gotten a compiler error 11 about not overriding it in workerVariant. But getThreadID() might 10 call other functions which you should override, but 9 are being invoked in the abstract class. You 8 should double check the definition of getThreadID() to 7 make sure you're not doing anything untoward 6 that would depend on the child class before 5 it's properly initialized.

A better solution 4 might be to separate this sort of multi-stage 3 initialization into a separate method, or 2 to design Director and baseWorkerClass such that they don't have 1 this sort of initialization-time interdependency.

Score: 3

Without seeing the full code I would hazard 12 a guess that you are stepping out of the 11 boundary of the memory block pointed to 10 by workerPtrArray. It would certainly make sense since 9 it complains about pure virtual function 8 being called. If the memory being dereferenced 7 is garbage then the runtime can't make sense 6 of it at all and weird things happen.

Try 5 to put asserts into critical places where 4 you are dereferencing the array to make 3 sure that indices make sense. I.e. limit 2 to 4 workers and make sure the id is less 1 than 4.

Score: 2

Pure virtual function called means that 10 a member which is pure in the base class 9 is called before the execution of the constructor 8 of the descendant is started. In non multi-thread 7 programs, this means directly or indirectly 6 in the constructor of the base class. In 5 a multi-threaded program, this can also 4 happen when the constructor launch the thread 3 in the constructor and the system execute 2 the thread before having terminated the 1 constructor.

Score: 2

During initialization classes are only partially 19 constructed. Specifically, constructors 18 have to be executed from the most ancestor 17 class up, so that each derived class'es 16 constructor can safely access its base members.

this 15 means that the vtable of a partially constructed 14 class can not be in its final state - if 13 virtual methods were allowed to call derived 12 classes, those methods would be called before 11 that classes constructor had been called.

Which 10 means that, during construction, pure virtual 9 functions are in fact, pure virtual. Modern 8 c++ compilers are getting better at catching 7 this - but its possible to in many cases 6 "bury" the illegal call in such a way that 5 the compiler doesn't notice the error.

Moral 4 of the story: dont do anything in your constructor 3 that will invoke a virtual function. It 2 just won't do what you expect. Even when 1 it isn't pure.

Score: 1

I didn't see the variant class being constructed 22 in any of your code samples. Are you sure 21 the id being passed is within range for 20 the worker array? Also, you're constructing 19 the objects using 'new', right? If you constructed 18 the object on the stack, it would register 17 itself with the Director, but after the 16 constructor returns the object will be immediately 15 destroyed, but the Director will retain 14 it's pointer to the object that was on the 13 stack.

Also, your baseWorkerClass destructor 12 should be virtual along with the workerVariant 11 destructor to make sure they get called 10 when you delete the array of baseWorkerClass.

From 9 my comment to another question, consider 8 using std::vector instead of the double 7 pointer. It's easier to maintain and understand 6 and removes your need to maintain the array.

It 5 seems like you've added an unnecessary layer 4 of abstraction here. I don't think the id 3 should really be part of the subclass interface. I 2 think something like this might work better 1 for you:

class baseWorkerClass
{
public:

    baseWorkerClass(int id) :
        id( id )
    {
    }

    virtual ~baseWorkerClass()
    {
    }

    int getThreadID(){ return id; };
    virtual int getSomeVariable() = 0;

protected:
    int id;
};

class workerVariant : protected baseWorkerClass
{
    public:

    workerVariant(int id) :
        baseWorkerClass( id )
    {
        Director::manageWorker(this);
    }

    virtual ~workerVariant()
    {
    }

    int getSomeVariable()
    {
        return someVariable;
    }

protected:
    int someVariable
};
Score: 0

Aren't you by any chance accessing the objects 13 after they are destructed? Because during 12 destruction the vtable pointers are gradually 11 "rolled back" so that vtable entries 10 will point to methods of the base class, some 9 of which are abstract. After deleting the 8 object, the memory could be left as it was 7 during the destructor of the base class.

I 6 suggest you try memory debugging tools, such 5 as valgrind or MALLOC_CHECK_=2. Also on unix it is quite easy to 4 get a stacktrace for such fatal errors. Just 3 run your application under gdb, or TotalView, and 2 at the point the error happens it will automatically 1 stop, and you can look at the stack.

Score: 0

I got this error message once, and though 4 it doesn't relate to the asker's exact case, I 3 add this in hopes that it might be useful 2 to others:

I fixed the issue by doing a 1 clean build.

More Related questions