7

I have a weird problem with a this-pointer in a base-class destructor.

Problem description:

I have 3 classes: A1, A2, A3

A2 inherits publicly from A1 and inherits privately from A3

class A2:private A3, public A1 {...}

A3 has a function getPrimaryInstance() ...that returns an A1-type reference to an A2 instance:

A1& A3::getPrimaryInstance()const{
    static A2 primary;
    return primary;
}

And the A3 constructor looks like this:

A3(){
    getPrimaryInstance().regInst(this);
}

(Where regInst(...) is a function defined in A1 that stores pointers to all A3 instances)

Similarly the A3 destructor:

~A3(){
    getPrimaryInstance().unregInst(this);
}

^Here is where the problem occurs!

When the static A2-instance named primary gets destroyed at program termination the A3-destructor will be called, but inside ~A3 I try to access a function on the same instance that I a destroying. => Access violation at runtime!

So I thought it would be possible to fix with a simple if-statement like so:

~A3(){
    if(this != (A3*)(A2*)&getPrimaryInstance()) //Original verison
    //if (this != dynamic_cast<A3*>(static_cast<A2*>(&getPrimaryInstance())))
    //Not working. Problem with seeing definitions, see comments below this post

        getPrimaryInstance().unregInst(this);
}

(Reason for double cast is the inheritance:)
A1 A3
. \ /
. A2
(But it's not important, could have just (int)-casted or whatever)

The kicker is that it still crashes. Stepping through the code with the debugger reveals that when my A2 primary-instance gets destroyd the this-pointer in the destructor and the address I get from calling getPrimaryInstance() doesn't match at all for some reason! I can't understand why the address that the this-pointer points to is always different from what it (to my limited knowledge) should be. :(

Doing this in the destructor:

int test = (int)this - (int)&getPrimaryInstance();

Also showed me that the difference is not constant (I briefly had a theory that there be some constant offset) so it's like it's two completely different objects when it should be the same one. :(

I'm coding in VC++ Express (2008). And after googling a little I found the following MS-article:
FIX: The "this" Pointer Is Incorrect in Destructor of Base Class

It's not the same problem as I have (and it was also supposedly fixed way back in C++.Net 2003). But regardless the symptoms seemed much alike and they did present a simple workaround so I decided to try it out:
Removed the not-working-if-statement and added in virtual in front of second inheritance to A2, like so:

class A2:private A3, public A1 {...} // <-- old version
class A2:private A3, virtual public A1 {...} //new, with virtual!

AND IT WORKED! The this-pointer is still seemingly wrong but no longer gives an access-violation.

So my big question is why?
Why does the this-pointer not point to the where it should(?)?
Why does adding virtual to the inheritance like above solve it (despite this still pointing somewhere else than &getPrimaryInstance())?
Is this a bug? Can someone try it in a non-MS environment?
And most importantly: Is this safe?? Sure it doesn't complain anymore, but I'm still worried that it's not doing what it should. :S

If anyone has knowledge of or experience from this and could help me understand it I would be very thankful since I'm still learning C++ and this is entirely outside of my current knowledge.

Michel de Ruiter
  • 7,131
  • 5
  • 49
  • 74
AnorZaken
  • 1,916
  • 1
  • 22
  • 34
  • 1
    This cast is not guranteed to be correct. `(A3*)(A2*)&getPrimaryInstance()`. You are casting up and down the class hierarchy using a C style cast (with multiple inheritance in play). Thus you need to use dynamic_cast<> – Martin York Dec 07 '10 at 18:45
  • Ok, so I tried it. But it doesn't compile. The reason it isn't obvious just from looking at the above post but goes as follows: In order to have A2 inherit from A3, A3 must be defined. In order for A3 to be able to cast to A2 it needs to see the definition of A2. So circular inclusion. – AnorZaken Dec 07 '10 at 19:35
  • ...This was one of the original problems I tried to tackle: I would like getPrimaryInstance() to return an A2 reference directly, but I can't! A3 hasn't seen the definition of A2! Since getPrimaryInstance() is declared in the base-class of A3 (not mentioned above) you get: error C2555: 'A3::getPrimaryInstance': overriding virtual function return type differs and is not covariant from 'A3Base::getPrimaryInstance' Simply: even if I declare the existence of A2 I don't know of any way to tell the compiler that A2 has A1 as base before I declare A2. :( If I could solve this it would be the great! – AnorZaken Dec 07 '10 at 19:41
  • Use forward declarations in header file to get around circular inclusion. Then in the source file include all the header files you need. – Martin York Dec 07 '10 at 19:58
  • No, as I mentioned forward declaration is not enough for dynamic_cast nor is it enough for inheritance. I can't achieve both in my code. Edit: to be fair, looking at my post I didn't explicitly state that forward declaration isn't enough. I said "needs to see the definition", sorry. ;) – AnorZaken Dec 07 '10 at 20:13
  • Yes. Inside A2.h you need to include A1.h and A3.h. But inside A3.h you can forward declare A1 as you only use references. Inside A3.cpp though you will need to include A3.h and A1.h – Martin York Dec 07 '10 at 21:31
  • This is essentially a lifetime of static instances issue, an ordering issue, a decrease of invariants issue: at program termination, during destruction of global objects, less and less objects are in well defined state, the objects invariants decrease. You seem to bury yourself in the technicalities like addresses of subjects, multiple inheritance... and the discussion on casts only adds confusion. – curiousguy May 27 '18 at 03:39

8 Answers8

4

You use of C casts is killing you.
It is especially liable to break in situations with multiple inheritance.

You need to use dynamic_cast<> to cast down a class hierarchy. Though you can use static_cast<> to move up (as I have done) but sometimes I think it is clearer to use dynamic_cast<> to move in both directions.

Avoid C style casts in C++ code

C++ has 4 different types of cast designed to replace the C style cast. You are using the equivalent of the reinterpret_cast<> and you are using incorrectly (Any good C++ developer on seeing a reinterpret_cast<> is going to go hold on a second here).

~A3(){
    if(this != (A3*)(A2*)&getPrimaryInstance())
        getPrimaryInstance().unregInst(this);
}

Should be:

~A3()
{
   if (this != dynamic_cast<A3*>(static_cast<A2*>(&getPrimaryInstance())))
   {    getPrimaryInstance().unregInst(this);
   }
}

The layout of an A2 object: (probably something like this).

     Offset   Data
A2   0x00   |------------------
     0x10   * A3 Stuff
            *------------------
     0x20   * A1 Stuff
            *------------------
     0x30   * A2 Stuff

In getPrimaryInstance()

 // Lets assume:
 std::cout << primary; // has an address of 0xFF00

The reference returned will point at the A1 part of the object:

std::cout << &getPrimaryInstancce();
// Should now print out 0xFF20

If you use C style casts it does not check anything just changes the type:

std::cout << (A2*)&getPrimaryInstancce();
// Should now print out 0xFF20
std::cout << (A3*)(A2*)&getPrimaryInstancce();
// Should now print out 0xFF20

Though if you use a C++ cast it should compensate correctly:

std::cout << static_cast<A2*>(&getPrimaryInstance());
// Should now print out 0xFF00
std::cout << dynamic_cast<A3*>(static_cast<A2*>(&getPrimaryInstance()));
// Should now print out 0xFF10

Of course the actual values are all very compiler dependent and will depend on the implementation layout. The above is just an example of what could happen.

Though as pointed out it is probably not safe calling dynamic_cast<> on an object that is currently in the processes of being destroyed.

So how about

Change regInst() so that it returns true for the first object registered. The getPrimaryInstance() will always by the first object to be created so it will allways be the first to register itself.

store this result in a local member variable and only unregister if you are not the first:

A3()
{
    m_IamFirst = getPrimaryInstance().regInst(this);
}

~A3()
{
    if (!m_IamFirst)
    {
         getPrimaryInstance().unregInst(this);
    }
}

Questions:

Why does the this-pointer not point to the where it should(?)?

It does. Just using C-Cast screws up the pointers.

Why does adding virtual to the inheritance like above solve it (despite this still pointing somewhere else than &getPrimaryInstance())?

Because it changes the layout in memory in such a way that the C-Cast is no longer screwing up your pointer.

Is this a bug?

No. Incorrect usage of C-Cast

Can someone try it in a non-MS environment?

It will do somthing similar.

And most importantly: Is this safe??

No. It is implementation defined how virtual members are layed out. You just happen to get lucky.

Solution: Stop using C style casts. Use the appropriate C++ cast.

Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Thanks for the great explanation! However aschepler said something about dynamic_cast in the destructor, and that it was not safe given how my code looks. So, is this really safe to use? But since you are the second person to mention this I'll edit my original post... – AnorZaken Dec 07 '10 at 19:16
  • @AnorZaken: His quite correct. So my explanation is why it crashes. Now we have to prevent it from crashing. – Martin York Dec 07 '10 at 19:23
  • 1
    @AnorZaken: Please see alternative solution. – Martin York Dec 07 '10 at 19:34
  • Hmm, will try it. It does mean wasting a /pointer-sized/ edit: brain error, *bool* -portion of memory for every A3 instance though. But since it's going to be very rare for an object at this level in the program to exist in more than a handful of instances... *thumbs up!* – AnorZaken Dec 07 '10 at 19:51
  • It works like a charm! :D When I was half way in making the necessary changes I even realized there was an even better solution tailored to how my code *actually* works (the code above only contained the parts I thought would be relevant to the problem). As I've mentioned in some other comment the A3 class considers A2 a friend. So to avoid registering the *primary* instance with regInst() (It's not an actual ingame object, just a storage location for A3-pointers of "real objects") the A2 constructor calls a private A3-constructor (which then set the bool instead of modifying A1-functions) :) – AnorZaken Dec 07 '10 at 20:09
  • "_Just using C-Cast screws up the pointers_" No. You made that up. – curiousguy May 27 '18 at 03:44
  • @MartinYork "_The trouble is that C-Cast is not what is required to convert A2* into A3*._" 1) Why wouldn't it do that conversion? 2) Why would `dynamic_cast` be more suitable? – curiousguy May 28 '18 at 00:44
  • @MartinYork "_A C cast is (not) dynamic_cast_" That's true: a C style cast never performs a `dynamic_cast`. My question is still: why does one need a `dynamic_cast` here? – curiousguy May 28 '18 at 01:33
  • @MartinYork I don't know the answer. I don't see why `dynamic_cast` would be more correct. – curiousguy May 28 '18 at 02:00
  • @MartinYork Does that section covers specifically: "You need to use a dynamic_cast to correctly convert the pointer from A2* into A3* (otherwise the pointer is screwed up and not usable)."? Does it say that a dynamic_cast works better than a C style cast? – curiousguy May 28 '18 at 02:06
  • @curiousguy Paragrph 5: `If Tis“pointer to cv1 B” and v has type“pointer to cv2 D” such that B is a base class of D, the result is a pointer to the unique B sub object of the D object pointed to by v. Similarly, if T is “reference to cv1 B” and v has type cv2 D such that B is a base class of D, the result is the unique B sub object of the D object referred to by v.69 In both the pointer and reference cases, the program is ill-formed if cv2 has greater cv-qualification than cv1 or if B is an inaccessible or ambiguous base class of D` – Martin York May 28 '18 at 02:09
  • @MartinYork Which confirms that a `dynamic_cast` doesn't work better than a `static_cast` or a C style cast. Thank you. – curiousguy May 28 '18 at 02:15
  • @MartinYork Reading that "Paragrph 5", it isn't even possible for a C++ programmer to determine the one cast operators is being discussed! That text describes a cast that is static, non polymorphic. This is even more evident because the quoted text does NOT say that `D` must be polymorphic. But in the description of `dynamic_cast` the next bullet requires polymorphism. This is because the quoted bullet is STATIC. – curiousguy May 28 '18 at 02:20
  • @MartinYork "_static cast works for casting up but not down a class hierarchy_" I have no idea what you are trying to say. What is a "down cast"? Can you give an example with the 3 classes in the question? (A1, A2, A3) – curiousguy May 28 '18 at 02:22
  • @curiousguy You are wrong. But I have provided the evidence needed. If you disagree feel free to downvote. I don't feel the need to correct you others will see you are obviously wrong. – Martin York May 28 '18 at 02:23
  • @curiousguy: Down => towards leaf => towards derived type. B => Base D => Derived. Cast from B -> D is a down cast. This requires a dynamic cast. The quote is from the ` 8.2.7 Dynamic cast [expr.dynamic.cast]`. So is specifically for down cast. You will not see the same quote in the static cast section. – Martin York May 28 '18 at 02:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/171895/discussion-between-curiousguy-and-martin-york). – curiousguy May 28 '18 at 02:29
  • @AnorZaken Curiousguy has convinced me my analysis above is wrong. Please put the tick mark on another question so I can delete it. – Martin York May 29 '18 at 17:29
  • Sorry but I don't see how that makes sense. Just edit at the top and say that the below content is wrong, and preferably why it is wrong if you have the time. Otherwise someone else may suggest or try the same thing you did. Knowing that something is wrong can be almost as valuable as knowing that something is correct. Deleting this answer would just serve to erase that knowledge. – AnorZaken Jun 07 '18 at 03:46
3
class A2 : private A3, public A1 {...} // <-- old version
class A2 : private A3, virtual public A1 {...} //new, with virtual!  

Why does adding virtual to the inheritance like above solve it (despite this still pointing somewhere else than &getPrimaryInstance())?

The reason this makes a difference is that virtual inheritance affects the order in which base class constructors and base class destructors are called.

The reason the numeric values of your this pointers aren't the same is that different "base class subobjects" of your complete object A2 primary; can and must have different addresses. Before any destructors are called, you can use dynamic_cast to get between A1* and A2*. When you're certain an A3 object is really the private base part of an A2, you can use a C-style cast to get from A3* to A2*.

But once the body of the destructor ~A2 has completed, which is the case within the ~A3 destructor, a dynamic_cast from A1* to A2* will fail and the C-style cast from A3* to A2* will produce undefined behavior, since there is no longer any A2 object.

So there's probably no way to do what you're trying unless you change how A2 primary; is stored/accessed.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • But does that mean that it _is_ indeed safe?? The regInst() is (**not** virtually) defined in A1, so if the A3 destructor is the first to be called when I destroy A2 then the A1 part should still exist and making calls to it should be safe? Right?? (PS. I would rep you up, but my own rep is to low atm. Mentioning this so you know I'm grateful for the information you've provided!) – AnorZaken Dec 07 '10 at 16:47
  • If you had separate pointers or references to the `A1` or `A3` objects, it might be safe to use them. But it is not safe to call `getPrimaryInstance()` while C++ is trying to destroy its local `static` variable. – aschepler Dec 07 '10 at 17:04
  • Does static variables in a class still remain valid until all instances of that class or derived classes has been destroyed? Destroying static members of a class before all instances of that class has been destroyed doesn't seem safe. If so then say A3 has a static bool. Then that bool should remain valid until after my A2 *primary* gets destroyed since it too inherits from, and therefor "is" an instance of, A3. So basically if I created a static bool *isShuttingDown* in A3 I could make the ~A2 destructor (first destructor of *primary* to be called) set it to true and skip the getPri.()-call? – AnorZaken Dec 07 '10 at 18:26
  • Hmm, tried it and it does seem to work. However I'm not convinced it's safe at all since the A3 class does contain another static variable already (a prototype instance of itself) and that gets destroyed before *primary* gets destroyed. So maybe I'm just lucky and the static bool *isShuttingDown* hasn't been destoyed yet due to pure coincidence... :/ Know anything about this? – AnorZaken Dec 07 '10 at 18:41
  • @aschepler: when you are really certain, you can use a `static_cast` (if there is no virtual inheritance there), C-style casts should be banned. – Matthieu M. Dec 07 '10 at 18:50
  • 1
    @Matthieu No, as bizarre as it is, this is a case where C-style cast can do something which no combination of C++-style casts can. 5.2.9p9 says `static_cast` may cast from base class `B*` to derived class `D*` if "a valid standard conversion ... exists" from `D*` to `B*`, which is not the case when the base is inaccessible. 5.4p7 specifies that certain casts "may be performed using the cast notation of explicit type conversion, even if the base class type is not accessible" – aschepler Dec 07 '10 at 19:31
  • 1
    @AnorZaken: Since `bool` is a POD ("plain old data") type, a static member with type `bool` is guaranteed to always be a valid object, even in constructors or destructors of static members with class type. – aschepler Dec 07 '10 at 19:37
  • 1
    @AnorZaken: To answer your other question, C++ does *not* guarantee that static members of a class are destroyed after all instances of that class. This would be impossible when a class has its own type as a static member, or `A` has a `static B x;` and `B` has a `static A y;`, etc. So do be careful using non-POD `static` members from a destructor. – aschepler Dec 07 '10 at 19:45
  • So then this would also be a solution? Correct? :) I'm sorry I've been so busy answering on all the great comments that people have provided here (soo fast that I've missed your post up till now) ;) Thank you very much for these reveling pieces of C++ information! – AnorZaken Dec 07 '10 at 20:27
  • I can't in good conscience recommend something like that, even if I do understand you right. In this conversation I was focusing on technical answers, but then there's style, which says all of this is horrible. There's almost certainly a way to do it without private inheritance. – aschepler Dec 07 '10 at 20:39
  • I know it's sort of horrible, and complex. If you're sure you're not comfortable in recommending this then I'll skip marking this as a solution. But since it *does* seem that it is technically ok and safe, I will mark it unless you're against it? If you want to know what this complexity is all about I can sum it up as follows: My code allows me to add a .h file describing an ingame object to my project and compile. And the object will show up and be usable ingame without requiring a single char being edited in any other file. :) Sure there are other ways I guess, but It became an obsession :P – AnorZaken Dec 07 '10 at 20:49
2

The virtual base class should only come into play if you have a diamond-inheritance structure, i.e. you're multiply inheriting classes sharing a common base class. Are you showing the whole actual inheritance tree of A1, A2 and A3 in your actual code?

Joris Timmermans
  • 10,814
  • 2
  • 49
  • 75
  • Well, no I'm not showing everything. There are a lot of small details I've left out... A1 inherits from Name. A2 has no inheritance left out, however (don't know if it matters) the A2 constructor is private and A3 is a friend to A2. Also A2 is friend to A3 so A2 can use a private constructor in A3 to avoid registering itself with regInst(..). A3 inherits from T2. T2 inherits from T1, and T1 inherits from Name. So I guess you are correct in that I have a diamond-inheritance structure. I know nothing of what this could do though? Is that the problem and why? – AnorZaken Dec 07 '10 at 16:20
  • (Also A1 has a protected constructor and is friend with T1 so T1 can create the first A1-instance - T1 defines a getPrimaryInstance that similarly to A3 returns a A1 reference, this time actually an A1 instance.) – AnorZaken Dec 07 '10 at 16:24
1

The problem may be that when A3::~A3() is called for an A2 object ,the A2 object is already destructed since ~A3() is called at the end of the destruction of A2. You cannot call getPrimary again since it's destructed already. NB: this applies to the case of the static variable primary

engf-010
  • 3,980
  • 1
  • 14
  • 25
  • Actually since there are multiple inheritance multiple destructors are called. (Unless I'm mistaken all the destructors are called and in the reverse order of how all the constructors where called when the A3 object was created). Also I can call getPrimaryInstance() in the destructor. I know it feels weird but I can do that. However it doesn't make much sense to do so because what I can't do is try to access members (or functions?) on the instance. So retrieving a reference to it is quite meaningless. But still: I was _trying_ Not to use it with my if-statement. But that failed :/ (why?) – AnorZaken Dec 07 '10 at 16:10
  • 1
    Yes ,destructors are called in the reverse order or construction. A2 in construct ,after A3 is constructed. So A3 is destructed after A2 is destructed. However when the static primary is destructed and ~A3 is called on it call getPrimaryInstance() which returns a object which is (at least partially) already destructed. That can't be good (Undefined Behaviour?). Whats is returned by getPrimaryInstance() when the static is/has-been destroyed. – engf-010 Dec 07 '10 at 16:24
  • What is returned is a reference to the instance. Basically its address. But you are absolutely correct: I shouldn't call it. My original intention was to avoid it, but I found no way to do that! :( So I found that article I linked to, and tried it. It's the only way I've found so far that doesn't give me an access violation. But I don't like calling it (I have no idea what is happening when I do...). My most important question was indeed **Is this safe??** I honestly don't know. If anyone knows how to avoid calling that function in the destructor that would be my preferred solution! – AnorZaken Dec 07 '10 at 16:36
  • TIP : You can make a A2& as a static member of A3 class and initialize it with getPrimaryInstance(). In the destructor use the & on that static member when you compare the this-pointer ,may be that will work. – engf-010 Dec 07 '10 at 16:43
  • You can also make an A3* as static member of A3 and initialize it to the A3 base class of GetprimaryInstance(). – engf-010 Dec 07 '10 at 16:47
  • You idea might work, however I'm not sure: there is one problem. I have multiple static variables. If I make them depend too much on each other (without a carefully selected portion of them being lazy-initialized) I will end up with undefined behavior since the order in which static variables are created at program startup is undefined. Fact is I have another static variable that needs to access getPrimaryInstance() in it's constructor, so if _primary_ wasn't lazy then it could happen that I would try to access _primary_ before it's created. Same goes with pointers. _Continues in next comment_ – AnorZaken Dec 07 '10 at 17:10
  • Can't grantee that memory has been allocated for the static pointer before I try to store something in it. (Unless ofcourse I've misunderstood how static variables get created at runtime). That's why I'm not using that approach. – AnorZaken Dec 07 '10 at 17:12
  • I understand the problem. It is a drawback of using references as return values (they must always exist). I can only reccomend to ponters instead ,then you can always check for NULL. – engf-010 Dec 07 '10 at 17:28
  • No, that's not what I meant. If memory hasn't been allocated for where the pointer should store it's "pointing-to"-address then I would be storing the address in a random place in memory. Atleast I think that can happen. A pointer is still a variable like any other. It too needs to have memory allocated. So a Null-check does nothing to tell if the variable exist yet. It only tells me if anything is stored in the pointers "point-to"-memory. – AnorZaken Dec 07 '10 at 18:00
  • Sorry about the misunderstanding. What I wanted to say Use a Pointer to a dynamically allocated object. Upon destruction of the primary you set the pointer to NULL. Let getPrimaryInstance return that pointer instead of a reference. – engf-010 Dec 07 '10 at 18:07
  • You mean to say it is defined that a dynamically allocated instance of A2 is surely going to get deallocated before the static pointer that stores it's address gets destroyed? Are you absolutely sure it goes like that? It can't happen that the pointer gets deallocated before the instance it points to get deallocated? Also is it possible to change what a local static pointer points to at runtime? That's what I mean by A pointer is also a variable. If the address where the pointer is stored gets freed before the instance then writing null (or anything else) there would be undefined behavior. – AnorZaken Dec 07 '10 at 18:47
  • 1
    This is my suggestion: In GetPrimaryInstance you have : if (this != primary) return primary; if (this == primary) delete primary; primry = NULL; return NULL; – engf-010 Dec 07 '10 at 19:13
  • I understand now. :) I think it could work. Sorry I'm not going to try it. I'm exhausted with back-pain and fever so barley sitting at the computer right now. :( But if someone else does and finds that it does indeed please tell a moderator to make this a solution. Edwin deserves the credit! Thank you Edwin! – AnorZaken Dec 07 '10 at 20:36
  • I think that solution is extremely dangerous. Any client "accidentally" calling GetPrimaryInstance on the primary instance is going to cause it to delete itself (which almost certainly will be unexpected by the client). A bug waiting to happen. In any case "GetPrimaryInstance" could be a static function if it is implemented as originally stated, and then "this" is not available. – Joris Timmermans Dec 08 '10 at 08:29
  • "_I can call getPrimaryInstance() in the destructor_" No, you cannot. – curiousguy May 27 '18 at 03:48
1

OP @AnorZaken commented:

...This was one of the original problems I tried to tackle: I would like getPrimaryInstance() to return an A2 reference directly, but I can't! A3 hasn't seen the definition of A2! Since getPrimaryInstance() is declared in the base-class of A3 (not mentioned above) you get: error C2555: 'A3::getPrimaryInstance': overriding virtual function return type differs and is not covariant from 'A3Base::getPrimaryInstance' Simply: even if I declare the existence of A2 I don't know of any way to tell the compiler that A2 has A1 as base before I declare A2. :( If I could solve this it would be the great!

So it sounds like you have something like:

class A3Base {
public:
  virtual A1& getPrimaryInstance();
};

And since class A2 cannot be defined before class A3, I would just skip the covariant return type. If you need a way to get the A2& reference from an A3, add that as a different method.

// A3.hpp
class A2;

class A3 : public A3Base {
public:
  virtual A1& getPrimaryInstance();
  A2& getPrimaryInstanceAsA2();
};

// A3.cpp
#include "A3.hpp"
#include "A2.hpp"

A1& A3::getPrimaryInstance() {
    return getPrimaryInstanceAsA2(); // no cast needed for "upward" public conversion
}
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • You are correct :) I will definitely look at implementing this once I'm feeling better. Hopefully tomorrow. Thank you once again aschepler! ;) – AnorZaken Dec 07 '10 at 21:01
0

When the static A2-instance named primary gets destroyed at program termination the A3-destructor will be called, but inside ~A3 I try to access a function on the same instance that I a destroying. => Access violation at runtime!

When static A2-instance named primary is destroyed the pointer to primary will point to "random" place in the memory. Therefore you are trying to access a random memory location and you get the runtime violation. It all has to do with in what order you call the destructors and make the call in the destructor.

try something like this:

delete a3;
delete a2-primary;

instead of

delete a2-primary;
delete a3;

I also think you might find this typecasting tutorial helpful.

Hope I could help you.

ejohansson
  • 2,832
  • 1
  • 23
  • 30
  • Sorry can't decide in what order to delete things. It's a static instance so it's destroyed after main() is finished (in an undefined order unless I'm mistaken). Also the pointer I get from calling getPrimaryInstance() in ~A3 is not random, the destruction process has not come that far yet... (with the debugger I have confirmed that the call to getPrimaryInstance() still returns the correct address, as in: same address as before the "object-deconstruction" process had started.) Also A3 is a part of A2 so I can't choose to delete half an object. – AnorZaken Dec 07 '10 at 17:00
0

There are 2 much bigger questions you should be asking:

  1. Why do I need to use private inheritance?
  2. Why do I need to use multiple inheritance for non-abstract base classes?

In most cases, the answer to #1 is you do not. Declaring a class that contains a data member to the other class usually handles this same situation in a much cleaner and easier to maintain code base.

In most cases, the answer to #2 is also you do not. It is a feature of the language that you use at your own peril.

I recommend you read the Meyers books and reevaluate your design pattern.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Well my design is indeed quite weird. You should have seen my previous attempt at trying to reach the goal for what this program should be able to do. It involved a class with a private class inside that inherited from its outer (the first) class! xD My teacher didn't even know you could do that when I mentioned it to him, he said he had never thought of even trying such a weird thing! xD For those in doubt it can be done, and works fine. But I found it wasn't necessary so I scraped it for it's brain twisting absurdity. – AnorZaken Dec 07 '10 at 17:21
  • **...** Why private? Only reason it inherits from A3 at all is because it needs (in a recursive manner) access to A3's base-classes versions of getPrimaryInstance(). These are non-static functions that returns a static (singleton-ish) instance. Again why? Because I need getPrimaryInstance() to be part of an abstract class used as an interface. So that's why it's not static to begin with. I'm sorry if it's hard to understand. It is for me too... o_o I was trying to isolate my original post to the problem at hand because the full structure of the program is complicated. – AnorZaken Dec 07 '10 at 17:26
-1

Short answer. It happens, because incorrect destructor is calling. For long answer check this and this And check Scott Meyer`s Effective C++. It covers such questions.

JohnGray
  • 656
  • 1
  • 10
  • 27
  • I currently have a headache so I'll read the full text later. But just skimmed the text and from the first link I got the impression that you're implying that the problem is because I'm not using a virtual destructor in A3. But this is not the problem. I realize it should be virtual so the code is not entirely correct, but I've tried that already and it has no impact on how the code runs (checked with the debugger). Basically the compiler is outsmarting my lazy coding and the correct destructor _is_ run. I will read the links in full later. Just wondering if this was what you thought I missed? – AnorZaken Dec 07 '10 at 15:50
  • I was trying to say, that you have to make all your destructors virtual. Don`t be confused if you don`t have any in A1 and A2. Actually, you have. You see, even if you will not specify any constructor or destructor in a class, the compiler will create a default one. Usually, it is not a big problem. But sometimes it could be painful, and you have to be aware of it. And my original thought was about compiler calling not proper destructor in not proper sequence. Maybe I'm not completely right. But I beleive, that it is, at least, one of your problems. – JohnGray Dec 07 '10 at 19:54
  • Them not being called in correct order was what the virtual keyword in the inheritance fixed (As explanied to me in one of the other comments). So you where partially right. (And aware of default-implementation.) But this was not enough to make the code safe since calling getPrimaryInstance() in ~A3 still was not a safe thing to do. Anyway I got it working now! :) Thanks! – AnorZaken Dec 07 '10 at 20:41
  • "_incorrect destructor is calling_" There is nothing in the posted code suggesting that is the case – curiousguy May 27 '18 at 03:51