I understand why I am getting the error I am getting (pure virtual function called). I am trying to call pure virtual functions from within the destructor of my base class shown below. However, I do not know how to rework my code to prevent this from happening. Here are the base and derived classes (the relevant portions anyway):
Base class:
TailFileManager::TailFileManager(const std::string &filename, const int fileOpenPeriod_ms)
: m_Stop(false)
{
m_WorkerThread.reset(new boost::thread(boost::bind(&TailFileManager::TailFile, this, filename, fileOpenPeriod_ms)));
}
TailFileManager::~TailFileManager()
{
m_Stop = true;
m_WorkerThread->join();
}
void TailFileManager::TailFile(const std::string &filename, const int fileOpenPeriod_ms)
{
std::ifstream ifs(filename.c_str());
while (! ifs.is_open())
{
boost::this_thread::sleep(boost::posix_time::milliseconds(fileOpenPeriod_ms));
ifs.open(filename.c_str());
}
ifs.seekg(0, std::ios::end);
while (! m_Stop)
{
ifs.clear();
std::string line;
while (std::getline(ifs, line))
{
OnLineAdded(line);
}
OnEndOfFile();
}
ifs.close();
}
Derived class:
ETSLogTailFileManager::ETSLogTailFileManager(const std::string &filename, const int heartbeatPeriod_ms)
: TailFileManager(filename, heartbeatPeriod_ms),
m_HeartbeatPeriod_ms(heartbeatPeriod_ms),
m_FoundInboundMessage(false),
m_TimeOfLastActivity(0)
{
}
ETSLogTailFileManager::~ETSLogTailFileManager()
{
}
void ETSLogTailFileManager::OnLineAdded(const std::string &line)
{
// do stuff...
}
void ETSLogTailFileManager::OnEndOfFile()
{
// do stuff...
}
You shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recovering Java or C# programmer, pay close attention to this Item, because this is a place where those languages zig, while C++ zags.
Re-work your design i.e you may call some cleanup function before object get destroyed, idea is just avoid virtual function during const/dest (if there are any!), if you are working with C++...
The rules for virtual invocation are different. C++ 2003, section 12.7 "Construction and Destruction", says:
Lets refresh some old memories ...
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructorâs own class or in one of its bases, but not a function overriding it in a class derived from the constructor or destructorâs class, or overriding it in one of the other base classes of the most derived object (1.8). If the virtual function call uses an explicit class member access (5.2.5) and the object-expression refers to the object under construction or destruction but its type is neither the constructor or destructorâs own class or one of its bases, the result of the call is undefined.
Because of this difference in behavior, it is recommended that you never invoke an object's virtual function while it is being constructed or destroyed.
Never Call Virtual Functions during Construction or Destruction
An Excerpt from Effective C++, Third Edition
by Scott Meyers
June 6, 2005
http://www.artima.com/cppsource/nevercall.html
As far as the C++ standard is concerned:
if you call a virtual function in a constructor or destructor, then the function is
dynamically dispatched as if its dynamic type were that of the current constructor/destructor being executed (§12.7/4)
if that function happened to a pure virtual, then this is undefined behavior (§10.4/6); the Itanium ABI defines the behavior: __cxa_pure_virtual is called.
So, you have a bit of a thorny issue...
A possible solution to the problem would be to break it down in two parts, in order to break the destruction in two parts. This could be achieved with a Strategy pattern:
provide a customizable interface, your strategy
provide a manager class that encapsulate the functionality and defers to the strategy for the customizable parts
Let's make it clearer:
class Interface {
public:
friend class Manager;
private:
virtual void finalize() = 0;
}; // class Interface
class Manager {
public:
explicit Manager(std::unique_ptr<Interface>&&);
~Manager();
private:
std::unique_ptr<Interface> _interface;
}; // class Manager
Manager::~Manager() {
_interface->finalize();
}
The trick ? At the point where finalize() is called the destruction of _interface has not begun yet! The call to the destructor will happen later; and thus you do not suffer from a half-dead object's fate.
I'll end this answer by a warning about join-ing a thread in a destructor now. Beware that destructors are automatically called in case of stack unwinding, it might therefore be dangerous to wait indefinitely while failing; especially if the thread is waiting for data that should be provided by the currently being unwound one... a classic case of dead-lock.
References (n3337):
§12.7/4 Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class.
§10.4/6 Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.
You write,
“I am trying to call pure virtual functions from within the destructor of my base class shown below.”
And the code in question is
TailFileManager::~TailFileManager()
{
m_Stop = true;
m_WorkerThread->join();
}
Happily in a single-threaded execution this couldn't possibly call a pure virtual function. But the thread that you're joining might call a pure virtual function on this object, possibly via a non-virtual member function. If so, then the issue is with the threading, specifically the lifetime management of this object.
Unfortunately you do not show the relevant code. Try to reduce things to a small, complete, working example. Where "working" in the sense that it reproduces the problem.
Depending on what system you're on this may work:
Set a breakpoint on the pure function call handler: __cxa_pure_virtual.
This worked for me using gdb: break __cxa_pure_virtual then, when the breakpoint was hit, up showed my code that was busted. (In my case, I am introducing a second thread and destruction was currently happening on a different thread while the object was being used.)
Documentation of __cxa_pure_virtual: https://www.swag.uwaterloo.ca/acd/docs/ItaniumC++ABI.htm#pure-virtual
Related
I'm having trouble understanding what's the reason for the crash in the following code :
class A {
public:
virtual ~A() { goo(); }
void goo() { absFoo(); }
virtual void absFoo() = 0;
};
class B : public A {
public:
void absFoo() { cout << "In B \n"; }
};
int main()
{
B b1;
b1.goo();
}
The main prints "In B" as expected, but in the end when it crashes, I can't debug it either, the compiler pops a weird message.
So my question is, when the destructor of A calls "goo()", does "absFoo()", crash
because we're referring to an abstract function?
Or does the compiler actually look for a definition in the derived classes? (And it doesn't exist anymore because it was destructed beforehand so it crashes)
I know that if we had called "absFoo()" directly from the destructor, the reason would have been the abstract function. But since here it's an outside function calling "absFoo()" I'm having trouble understanding the real reason.
What happens when a destructor calls an abstract function
First, let us consider what happens when a destructor calls any virtual function (the same applies to the constructor by the way): When a virtual function foo is called in the destructor of T, the call will not be dispatched dynamically to an implementation in a derived type (the lifetime of any derived object has already ended), but statically to the implementation T::foo.
If T::foo is pure virtual, then calling it without dynamic dispatch will have undefined behaviour. That is what happens when a pure virtual function is (indirectly) called in a destructor (or constructor).
Just to complement the already accepted answer, this is the documentation from cppreference.
When a virtual function is called directly or indirectly from a
constructor or from a destructor (including during the construction or
destruction of the class’s non-static data members, e.g. in a member
initializer list), and the object to which the call applies is the
object under construction or destruction, the function called is the
final overrider in the constructor’s or destructor’s class and not one
overriding it in a more-derived class.
In other words, during construction or destruction, the more-derived classes do not exist.
As the object is deconstructed, the vtable is updated to match the new status of the object.
Since you've removed the last function, the compiler will do whatever it considers fit; which in the case of a debug compilation in visual studio, will fallback to an abort reporting that a pure virtual function was called.
The vtable however is not part of the standard, it's an implementation detail, and there's no requirement for your program to crash; it's just what is considered the nicest thing to do when you've called a pure virtual function.
I was trying to familiarize myself with the OOP concepts but could not quite understand the concept of virtual.
One can create a virtual destructor but not a virtual constructor. Why?
How are virtual destructors handled internally? I mean the link Virtual Destructors illustrates the concept but my question is how the vptr of both the vtables (Derived and Base) are called? (In case of virtual member functions when such a scenario occurs generally the function that vptr of Derived class points to is only called)
Are there any other scenarios where one may need to use a virtual destructor?
Can anyone please help me understand the above concepts with links/examples?
First, a little about the difference between virtual functions and non-virtual functions:
Every non-virtual function-call that you have in your code can be resolved during compilation or linkage.
By resolved, we mean that the address of the function can be computed by the compiler or the linker.
So in the object code created, the function-call can be replaced with an op-code for jumping to the address of that function in memory.
With virtual functions, you have the ability to invoke functions which can be resolved only during runtime.
Instead of explaining it, let's run through a simple scenario:
class Animal
{
virtual void Eat(int amount) = 0;
};
class Lion : public Animal
{
virtual void Eat(int amount) { ... }
};
class Tiger : public Animal
{
virtual void Eat(int amount) { ... }
};
class Tigon : public Animal
{
virtual void Eat(int amount) { ... }
};
class Liger : public Animal
{
virtual void Eat(int amount) { ... }
};
void Safari(Animal* animals[], int numOfAnimals, int amount)
{
for (int i=0; i<numOfAnimals; i++)
animals[i]->Eat(amount);
// A different function may execute at each iteration
}
As you can probably understand, the Safari function allows you to be flexible and feed different animals.
But since the exact type of each animal is not known until runtime, so is the exact Eat function to be called.
The constructor of a class cannot be virtual because:
Calling a virtual function of an object is performed through the V-Table of the object's class.
Every object holds a pointer to the V-Table of its class, but this pointer is initialized only at runtime, when the object is created.
In other words, this pointer is initialized only when the constructor is called, and therefore the constructor itself cannot be virtual.
Besides that, there is no sense for the constructor to be virtual in the first place.
The idea behind virtual functions is that you can call them without knowing the exact type of the object with which they are called.
When you create an object (i.e., when you implicitly call a constructor), you know exactly what type of object you are creating, so you have no need for this mechanism.
The destructor of a base-class has to be virtual because:
When you statically allocate an object whose class inherits from the base-class, then at the end of the function (if the object is local) or the program (if the object is global), the destructor of the class is automatically invoked, and in turn, invokes the destructor of the base-class.
In this case, there is no meaning to the fact that the destructor is virtual.
On the other hand, when you dynamically allocate (new) an object whose class inherits from the base-class, then you need to dynamically deallocate (delete) it at some later point in the execution of the program.
The delete operator takes a pointer to the object, where the pointer's type may be the base-class itself.
In such case, if the destructor is virtual, then the delete operator invokes the destructor of the class, which in turn invokes the destructor of the base-class.
But if the destructor is not virtual, then the delete operator invokes the destructor of the base-class, and the destructor of the actual class is never invoked.
Consider the following example:
class A
{
A() {...}
~A() {...}
};
class B: public A
{
B() {...}
~B() {...}
};
void func()
{
A* b = new B(); // must invoke the destructor of class 'B' at some later point
...
delete b; // the destructor of class 'B' is never invoked
}
One can create a virtual destructor but not a virtual constructor. Why?
Virtual functions are dispatched according to the type of the object they're called on. When a constructor is called, there is no object - it's the constructor's job to create one. Without an object, there's no possibility of virtual dispatch, so the constructor can't be virtual.
How are virtual destructors handled internally?
The internal details of virtual dispatch are implementation-defined; the language doesn't specify the implementation, only the behaviour. Typically, the destructor is called via a vtable just like any virtual function.
how the vptr of both the vtables (Derived and Base) are called?
Only the most-derived destructor will be called virtually. All destructors, virtual or not, will implicitly call the destructors of all member and direct base-class subobjects. (The situation is slightly more complicated in the presence of virtual inheritance; but that's beyond the scope of this question).
Are there any other scenarios where one may need to use a virtual destructor?
You need one in order to support polymorphic deletion; that is, to be able to delete an object of derived type via a pointer to a base type. Without a virtual destructor for the base type, that's not allowed, and will give undefined behaviour.
because a Virtual function is invoked at runtime phase, however constructors are invoked at initialization phase, object is not constructed. So it's meaningless to have a virtual constructor.
a. the reason why only the base class desctructor is invoked in your link, the destructor is not marked as virtual, so the desctructor address is linked to Base class destructor at compile/link time, and obviously the type of the pointer is Base instead of Derived at compile time.
b. for why both of Base and Derived constructors are invoked after adding virtual to Base desctructor. It's same behavior like below:
Derived d; // when d exits the lifecycle, both Derived and Base's desctructor will be invoked.
Suppose when you have at least one virtual function, you should have a virtual desctructor.
One can create a virtual destructor but not a virtual constructor.
Why?
I'll try and explain this in layman's terms.
A class in c++ only exists after it's constructor completes. Each base class exists prior to initialisation of derived class and its members (vtable links included). Hence, having a virtual constructor does not make sense (since to construct, you need to know the type). Furthermore (in c++), calling virtual functions from a constructor does not work (as the derived class's vtable part has not been set up). If one thinks about it carefully, allowing virtual functions to be called from a contructor opens up a can of worms (such as what if virtual functions of derived classes are called prior to member initialization).
As far as destructors are concerned, at the point of destruction, the vtable is "intact", and we (c++ runtime) are fully aware of the type (so to speak). The destructor of the most derived part of the type is found (if virtual, through vtable), and therefore that destructor, and naturally that of all bases can be called.
How are virtual destructors handled internally? I mean the link
Virtual Destructors illustrates the concept but my question is how the
vptr of both the vtables (Derived and Base) are called?
Destructors are handled the same as normal virtual functions (that is, there addresses are looked up in a vtable if they are virtual at the expense of one (perhaps 2?) extra level/s of indirection). Furthermore, c++ guarantees that all base destructors shall execute (in opposite order of construction which relies on order of declaration) after completion of a derived destructor.
One can mimick/simulate virtual construction by using patterns such as the prototype pattern (or cloning), or by using factories. In such cases either an instance of the real type exists (to be used polymorphically), or a factory exists (deriving from abstract factory), that creates a type (via virtual function) based on some knowledge provided.
Hope this helps.
I assume we have a Base class A, and it's derived B.
1.: You can delete B via an A pointer, and then the correct method is to call the B destructor too.
However, you just can't say, that a B object should be created while you actually just call the A constructor. There is just not such a case.
You can say:
A* a = new B ();
or
B b;
But both directly call the B's constructor.
2.: Well, i am not entirely sure, but i guess it will iterate through the relevant part of the class hierarchy, and search for the closest call of the function. If a function is not virtual, it stop iterating and call it.
3.: You should always use virtual destructor, if you want to inherit something from that class. If it's a final class, you shouldn't.
I wasted a couple of days trying to discover why my derived virtual destructors were not being called before discovering the answer so hopefully I can save other a lot of grief with this reply.
I started using derived classes three and four levels deep in my project. Virtual functions seemed to work fine but then I discovered I had massive memory leaks because my destructors were not being called. No compiler or runtime error - the destructors just were not being called.
There is a ton of documentation and examples about this on the web but none of it was useful because my syntax was correct.
I decided that if the compiler wasn't going to call my destructors, I needed to create my own virtual destruct method to call. Then I got the compiler error that solved the problem - "class if a Forward Reference". Adding an include for the derived class header files in the base class solved the problem. The compiler needs the class definition to call the destructor!
I suggest when creating a new derived class, include the header file in the base and intermediate classes. Probably also a good idea to add conditional debug code to your destructors to check that they are bing called.
Bob Rice
I understand why this is happening, but I'm stuck trying to resolve it...here is what my code is doing when the error is generated (thus, leading to a crash) when my program exits...
pure virtual method called
SomeClass::~SomeClass()
{
BaseClassObject->SomePureVirtualMethod(this);
}
void DerivedClass::SomePureVirtualMethod(SomeClass* obj)
{
//Do stuff to remove obj from a collection
}
I never have a call to new SomeClass but I have a QList<SomeClass*> which I append SomeClass* objects to. The purpose of this destructor in SomeClass is to tell DerivedClass to remove a specific instance of SomeClass from it's collection of QList<SomeClass*>.
So, in a concrete example...
BaseClass = Shape
DerivedClass = Triangle
SomeClass = ShapeProperties which owns a reference to Shape
So, I never have a call to new ShapeProperties but I have a QList<ShapeProperties*> inside of Triangle. The destructor in ShapeProperties is to tell Triangle to remove a specific property of ShapeProperties from it's collection of QList<ShapeProperties*>.
By the time your destructor is called, the destructor of inherited classes has already been called. Within constructors and destructors, the dynamic type of the object can effectively be considered to be the same as the static type. That is, when you call virtual methods from within your constructors/destructors it's not the overriden versions of them that are called.
If SomePureVirtualMethod needs to be called at the destructor, then you will have to call it within the destructor of the class where the actual definition of the method you want is.
When you call the virtual method in the destructor of the Base class SomeClass it calls the method(SomePureVirtualMethod()) of the Base class SomeClass which is a pure virtual method with no definition. And hence the error.
Why does this happen?
The type of this in constructor or destructor is of the type whose constructor or destructor is being called and hence dynamic dispatch doesn't work in constructors and destructors as you would expect it to work in all other functions.
Why does it crash?
Because calling a pure virtual function from constructor or destructor is an Undefined Behavior.
C++03 10.4/6 states
"Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined."
How to avoid it?
Just ensure that you don't call a pure virtual function from constructor or destructor.
Don't call virtual methods in constructor or destructor unless you understand the dynamics involved.
There is another reason why this might happen, depending on your compiler and system, and that is from a dangling reference. Paul S. R. Chisholm explains the possible state of freed memory:
The memory might be marked as deallocated.
The memory might be deliberately scrambled.
The memory might be reused.
The memory might have been left exactly the way it was.
The last is an interesting case. What was the object "exactly the way
it was"? In this case, it was an instance of the abstract base class;
certainly that's the way the vtbl was left. What happens if we try to
call a pure virtual member function for such an object?
"Pure virtual function called".
First of all, I searched this problem and found a lot of similiar questions, but I couldn't find an answer that fixed my problem. I am very sorry if that is just me being dumb.
What I am trying to do is make the constructor of an abstract class call a function that is pure virtual. In Java, this works, because the subclass provides the implementation of the abstract method that is called. However, in C++, I get this linker error:
test.o:test.cpp:(.text$_ZN15MyAbstractClassC2Ev[MyAbstractClass::MyAbstractClass
()]+0x16): undefined reference to `MyAbstractClass::initialize()'
collect2: ld returned 1 exit status
Here is my code:
#include <iostream>
class MyAbstractClass {
protected:
virtual void initialize() = 0;
public:
MyAbstractClass() {
initialize();
}
};
class MyClass : public MyAbstractClass {
private:
void initialize() {
std::cout << "yey!" << std::endl;
}
};
int main() {
MyClass *my = new MyClass();
return 0;
}
As a further explanation of what I am trying to do, here is code in Java that achieves my goal:
public abstract class MyAbstractClass {
public MyAbstractClass() {
initialize();
}
protected abstract void initialize();
}
public class MyClass extends MyAbstractClass {
protected void initialize() {
System.out.println("Yey!");
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
}
}
This code prints "Yey!". Any help much appreciated!
MyAbstractClass() {
initialize();
}
That will not perform a virtual dispatch to MyClass::initialize(), because at this stage of the object's construction its MyClass parts haven't been created yet. Thus you really are invoking MyAbstractClass::initialize() and, as such, it must be defined. (Yes, pure virtual member functions can be defined.)
Try to avoid invoking virtual member functions from constructors, because this sort of stuff will happen and catch you out. It rarely makes sense to do it.
Also, try to avoid initialize() functions; you already have constructors to play with.
Update
Actually, though you may take the above as read for any other virtual member function, invoking a pure virtual member function from the constructor yields Undefined Behaviour. So don't even try!
In C++, you can't call a pure virtual function from a constructor or destructor (even if it has a definition). If you call a non-pure one, then it will be dispatched as if the object's type were the class under construction, so you'll never be able to call a function defined in a derived class.
In this case, you don't need to; the derived class's constructor will be called after the base class's, so you get the desired result from:
#include <iostream>
class MyAbstractClass {
public:
MyAbstractClass() {
// don't do anything special to initialise the derived class
}
};
class MyClass : public MyAbstractClass {
public:
MyClass() {
std::cout << "yey!" << std::endl;
}
};
int main() {
MyClass my;
return 0;
}
Note that I also changed my to an automatic variable; you should get in the habit of using them whenever you don't need dynamic allocation, and learn how to use RAII to manage dynamic resources when you really do need them.
Let me quote Scott Meyers here (see Never Call Virtual Functions during Construction or Destruction):
Item 9: Never call virtual functions during construction or destruction.
I'll begin with the recap: you shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recovering Java or C# programmer, pay close attention to this Item, because this is a place where those languages zig, while C++ zags.
The issue: during object construction the virtual function table might not yet be ready. Just imagine that your class is eg. fourth in line of inheritance. Constructors are called in inheritance order, so while calling this pure virtual (or even if it was non-pure) you would like the base class to call initialize for an object that is not yet complete!
The C++ side has been handled in other answers, but I want to add a remark on the Java side of it. Calling a virtual function from a constructor is a problem in all cases, not just in C++. Basically what the code is trying to do is execute a method on an object that has not yet been created and that is an error.
The two solutions implemented in the different languages differ in trying to make some sense of what your code is trying to do. In C++ the decision is that during construction of a base object, and until construction of the derived object starts, the actual type of the object is base, which means that there won't be dynamic dispatch. That is, the type of the object at any time is that of the constructor being executed[*]. While this is surprising to some (you among others), it provides a sensible solution to the problem.
[*] Conversely the destructor. The type also changes as the most derived constructors complete.
The alternative in Java is that the object is of the final type from the beginning, even before construction has completed. In Java, as you demonstrated, the call will be dispatched to the final overrider (I am using C++ slang here: to the last implementation of the virtual function in the execution chain), and that can cause unwanted behavior. Consider for example this implementation of initialize():
public class MyClass extends MyAbstractClass {
final int k1 = 1;
final int k2;
MyClass() {
k2 = 2;
}
void initialize() {
System.out.println( "Constant 1 is " + k1 + " and constant 2 is " + k2 );
}
}
What is the output of the previous program? (Answer at the bottom)
More than just a toy example, consider that MyClass provides some invariants that are set at construction time and hold for the whole lifetime of the object. Maybe it holds a reference to a logger on which data can be dumped. By looking at the class, you can see that the logger is set in the constructor and assume that it cannot be reset anywhere in the code:
public class MyClass extends MyAbstractClass {
Logger logger;
MyClass() {
logger = new Logger( System.out );
}
void initialize() {
logger.debug( "Starting initialization" );
}
}
You probably see now where this is going. By looking at the implementation of MyClass there does not seem to be anything wrong at all. logger is set in the constructor, so it can be used in all methods of the class. Now the problem is that if MyAbstractClass calls on a virtual function that gets dispatched then the application will crash with a NullPointerException.
By now I hope that you understand and value the C++ decision of not performing dynamic dispatch and thus avoid executing functions on objects that have not yet been fully initialized (or conversely have already been destroyed, if the virtual call is in the destructor).
(Answer: this might depend on the compiler/JVM, but when I tried this long long time ago, the line printed Constant 1 is 1 and constant 2 is 0. If you are happy with that, fine by me, but I found that to be surprising... The reason for the 1/0 in that compiler is that the process of initialization first sets the values that are in the variable definition, and then calls the constructors. This means that the first step of construction would set k1 before calling MyAbstractBase constructor, that would call initialize() before MyBase constructor has run and set the value of the second constant).
During construction and destruction, the virtual table is set up appropriately for the base subobject being constructed or destroyed. This is the theoretically correct thing to do, because the more-derived class is not alive (its lifetime either hasn't yet started or has already ended).
As already explained by #Seth, you cannot call virtual functions in a constructor. More specifically, the virtual dispatch mechanism is disabled during construction and destruction. Either make your initialize member function nonvirtual and implement it in the base class, or have the user call it explicitly.
I'm working on building Cppcheck on AIX with the xlC compiler (see previous question). Checker classes all derive from a Check class, whose constructor registers each object in a global list:
check.h
class Check {
public:
Check() {
instances().push_back(this);
instances().sort();
}
static std::list<Check *> &instances();
virtual std::string name() const = 0;
private:
bool operator<(const Check *other) const {
return (name() < other->name());
}
};
checkbufferoverrun.h
class CheckBufferOverrun: public Check {
public:
// ...
std::string name() const {
return "Bounds checking";
}
};
The problem I appear to be having is with the instances().sort() call. sort() will call Check::operator<() which calls Check::name() on each pointer in the static instances() list, but the Check instance that was just added to the list has not yet had its constructor fully run (because it's still inside Check::Check()). Therefore, it should be undefined behaviour to call ->name() on such a pointer before the CheckBufferOverrun constructor has completed.
Is this really undefined behaviour, or am I missing a subtlety here?
Note that I don't think the call to sort() is strictly required, but the effect is that Cppcheck runs all its checkers in a deterministic order. This only affects the output in the order in which errors are detected, which causes causes some test cases to fail because they're expecting the output in a particular order.
Update: The question as above still (mostly) stands. However, I think the real reason why the call to sort() in the constructor wasn't causing problems (ie. crashing by calling a pure virtual function) is that the Check::operator<(const Check *) is never actually called by sort()! Rather, sort() appears to compare the pointers instead. This happens in both g++ and xlC, indicating a problem with the Cppcheck code itself.
Yes, it's undefined. The standard specifically says so in 10.4/6
Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.
It is true that calling a pure virtual function from a constructor is always an undefined behaviour.
The virtual pointer can not be assumed to be set until the constructor has run completely (closing "}"), and hence any call to a virtual function (or pure virtual function) has to be setup at the time of compilation itself (statically bound call).
Now, if the virtual function is pure virtual function, the compiler will generally insert its own implementation for such pure virtual function, the default behavior of which is to generate a segmentation fault. The Standard does not dictate what should be the implementation of a pure virtual function, but most of C++ compilers adopt aforesaid style.
If your code is not causing any runtime mischief demeanour, then it is not getting called in the said call sequence. If you could post the implementation code for below 2 functions
instances().push_back(this);
instances().sort();
then maybe it will help to see what's going on.
As long as object construction isn't finished, a pure virtual function may not be called. However, if it's declared pure virtual in a base class A, then defined in B (derived from A), the constructor of C (derived from B) may call it, since B's construction is complete.
In your case, use a static constructor instead:
class check {
private Check () { ... }
public:
static Check* createInstance() {
Check* check = new Check();
instances().push_back(check);
instances().sort();
}
...
}
I think your real problem is that you've conflated two things: the Checker base class, and some mechanism for registering (derived) instances of Check.
Among other things, this isn't particularly robust: I may want to use your Checker classes, but I may want to register them differently.
Maybe you could do something like this: Checker get a protected ctor (it's abstract anyway, and so only derived classes ought to be calling the Checker ctor).
Derived classes also have protected ctors, and a public static method (the "named constructor pattern") to create instances. That creating method news up a Checker subclass, and them passes it (fully created at this point) to a CheckerRegister class (which is also abstract, so users can implemented their own if need be).
You use whatever singleton pattern, or dependency injection mechanism, that you prefer, to instantiate a Checkerregister and make it available to Checker subclasses.
One simple way to do this would be to have a getCheckerRegister static method on Checker.
So a Checker subclass might look like this:
class CheckBufferOverrun: public Check {
protected:
CheckBufferOverrun : Check("Bounds checking") {
// since every derived has a name, why not just pass it as an arg?
}
public:
CheckBufferOverrun makeCheckBufferOverrun() {
CheckBufferOverrun that = new CheckBufferOverrun();
// get the singleton, pass it something fully constructed
Checker.getCheckerRegister.register(that) ;
return that;
}
If it looks like this will end up being a lot of boilerplate code, write a template. If you worry that because each template instance in C++ is a real and unique class, write a non-templated base class that will register any Checker-derived.