0

I am trying to wait for a thread to die in the destructor of a pure virtual class. The code compiles just fine, and appears to make sense. However, the following error occurs when running it:

pure virtual method called
terminate called without an active exception
Aborted (core dumped)

Here is my program:

#include <boost/thread.hpp>
#include <iostream>

class Test {
    protected:
        int x;
        boost::thread th;
    public:
        Test(void): x(10) {};
        ~Test(void);
        virtual void operator()(void);
        void run(void);
        virtual void a(void) = 0;
        void wait(void);
};

Test::~Test(void) {
    this->wait();
}

void Test::operator()(void) {
    this->a();
    x += 10;
    std::cout << "Current Value: " << x << std::endl;
}

void Test::run(void) {
    this->th = boost::thread(&Test::operator(), this);
}

void Test::wait(void) {
    this->th.join();
}

class Test1 : public Test {
    public:
        virtual void a(void);
};

void Test1::a(void) {
    x--;
}

main() {
    Test1 test;
    test.run();
    //test.wait();
}

The expected result is 19. I can get it by putting the call to Test::wait() in main() before the object leaves scope rather than into the destructor. The exception does not happen when the pure-virtual method a() is removed from Test.

My questions then are:

  1. What virtual method is the error referring to since Test::a() is not in the destructor's call chain?
  2. Why is the code compiling if there is such an ambiguity?

I am guessing that the answer to one will be the answer to the other...

P.S. In case it matters, I am running g++ (GCC) 4.9.1 20140903 (prerelease) on Arch Linux, kernel version 3.17.2-1 in GNU bash, version 4.3.30(1)-release

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264

1 Answers1

3

Problem is related to the problem, when you call a virtual function from constructor/destructor. In this case wait() called from a base destructor - Test::~Test(), which means that derived class Test1 is already destructed and virtual table updated to base class Test. Looks like virtual call in separate thread happens after that and you get pure virtual method call. So behavior is like you indirectly call a() from destructor of Test.

When you call wait() explicitly it waits before test1 instance being destructed and it works fine.

Unrelated to this problem, dtor of class Test should be virtual, as you have virtual method(s).

Slava
  • 43,454
  • 1
  • 47
  • 90
  • Wow. That completely explains everything. Did not see that coming. – Mad Physicist Nov 06 '14 at 21:36
  • I was aware of the last point about virtual destructor. In this particular case it would not/did not make a difference. This is just an interesting puzzler with a clean workaround. – Mad Physicist Nov 06 '14 at 21:38
  • Of course: `Current Value: 19`. The problem in your original code is that the *part of the object that contains your implemented `a()`* is destructed too early, because only the base class destructor blocks (waiting for the thread to finish). If the derived class constructor (which is called first) blocks, nothing bad happens, because the vtable cannot be reverted to the base class version before the thread has finished. Of course I am only referring to the explicit `wait()` in your `main()` when I say "avoid calling `wait()`". – Oguk Nov 06 '14 at 22:24
  • a) Of course not, I only said "avoid calling it explicitly" (in `main()`). b) Of course, why do you think I disagree with that? c) No. The only pure virtual method is `a()`. The error occurs, because `a()` is called *within your thread* after the derived class has already been destructed (hence the vtable looks like the one of the base class), because `test` went out of scope and the destructor of `Test1` does nothing to prevent destruction even if the thread is currently running (and, as in your case `a()` hasn't been called yet). Only the `Test` part of the object is kept alive. – Oguk Nov 06 '14 at 22:39