I have a C++ standard related question. Let's say I have 2 derived object D1 and D2 (which may contain class D virtual functions) of an identical class base B. Now, I create base pointers bpD1 and bpD2 to those objects.
1) Are bpD1 and bpD2 *guaranteed* to be different if the derived part of D1 and D2 are different even though the base part have identical values, OR,
2) does the c++ standard authorise a smart optimised compiler to use an identical value for bpD1 and bpD2 when it later sees in the code that the derived (different) parts are never actually used for these 2 derived object and thus they are functionnaly equal?

Where in the standard is this written to be authorised or prohibited?

The reason of the question is that I want to use those bpD1 and bpD2 to check if D1 and D2 themselves are identical by simply checking if bpD1=bpD2, and I am afraid a very optimised compiler could say that bpD1=bpD2 even though D1 is different from D2 (if the optimiser finds that the base part of D1 and D2 are equal and sees that I never later use the non-base part of D1 and D2).

Help on this matter would be greatly apreciated. Thanks in advance.

Recommended Answers

All 10 Replies

I think you are very confused, no offence. It seems you don't understand the difference between an object and a class. An object is an instance of a class, in other words, the class is the type, and an object is a variable of that type. So, if you have two pointers to two objects, they will never be equal even if they are of the same class, because they point to two different instances (or objects) which are at different locations in the memory (and thus, have different addresses). So, that fact just nullifies your question completely.

If this was not what you meant by your questions, please rephrase and provide a bit of code to illustrate the class hierarchy and use-case you are talking about.

N.B: if you want to compare two pointers, you have to use two equal signs
"==", not one (that is an assignment operator).

Thanks Mike for your reply. I am well aware of the difference you mentionned and have been programming in C++ for > 2 years.
I may have likely not made myself clear enough.
You said: "the instance point at different locations in the memory".
But that is in essence what I am kind of disputing: is this specifically a requirement of the standard? (I very much doubt so!) ?
For example, many C++ programmers use the "copy on write" (typically use for strings) optimisation where 2 different objects share the same memory location if their content are identical, with a copy to a different location only when the content of the objects become different (hence the name of the optimisation: copy on "write").
So you can view my question as: does the C++ standard permits a C++ compiler/optimiser to use a sort of "copy on write" optimisation for the specific case I mentionned?

You say "2 different objects share the same memory location if their content are identical."

The thing is: If they share the same memory location, they are not different objects.

To make myself clearer I will give a specific example:

struct B{
  const int v=100;
  virtual int get_derived_value()=0;

};
struct D1:B{
  int v1;
  int get_derived_value(){return v1;}
  D1():v1(1000){}
};
struct D2:B{
  int v2;
  int get_derived_value(){return v2;}
  D2():v2(2000){}
}

void myfct(){
  D1 d1;
  D2 d2;
  B bp1=&d1;
  B bp2=&d2;
    /*
     at this point without optimisation bp1 and bp2 are 2 different value since they are pointer to different object (located at different memory)
   BUT
   a smart compiler could optimise this by seeing that the next lines (below) of this function never use the derived part of d1 and d2 and that the base part has an identical content (v=100) therefore bp1 and bp2 points to 2 objects that have identical content and therefore should behave the same way in that part of the code (even though the derived part - which is not use in that code - is different)
  */
  if (bp1==bp2){
    // ...do something that does not use get_derived_value
  }
}

Correction: I obviously forgot the *:
Replace

B bp1=&d1
B bp2=&d2

with

B * bp1=&d1;
b * bp2=&d2;

>>does the C++ standard permits a C++ compiler/optimiser to use a sort of "copy on write" optimisation for the specific case I mentionned?

No. C++ implements value-semantics. This means that two different objects can never be two references to the same object. You can, of course, have two references or pointers to the same object, but that is entirely under your control, the compiler has little to do with that.

There are certain optimizations that the compilers are allowed to do when it comes to base versus derived class pointers. That is, if you hold a pointer to a base-class object, but the context makes it obvious to the compiler that the object is of a particular derived class, the compiler is allowed to by-pass the virtual function call and make an ordinary function call to the function it knows will be called anyways via the virtual dispatch mechanism. For example, a trivial case:

#include <iostream>

struct B {
  virtual void print() const = 0;
};

struct D : B {
  virtual void print() const { std::cout << "Hello World!" << std::endl; };
};

int main() {
  D d1;
  B* b1 = &d1;
  b1->print(); //here, the compiler will most likely by-pass the virtual table look-up because it is clear from the context that b1 actually points to an object of class 'D', and so, it can call D::print() directly.
  return 0;
};

You can try the above and output the assembly listing for it and you will see that the virtual table look-up (or virtual dispatch) is by-passed and optimized away. But note here, that the compiler is allowed to do this only when it is absolutely certain, from the local context, that there is no possible way that the base-class pointer could point to anything other than the derived class in question. In other words, the compiler is allowed to do this optimization only if it is guaranteed not to change the behaviour of the program. And this rule holds true for almost all optimization opportunities in C++ (with the notable exception of the "return-value-optimization", which is allowed to change behaviour by opimizing away some constructor/destructor calls).


EDIT: From your last post, clearly NO. To the compiler, you are creating two different objects, there is no way, absolutely no way, that the compiler would be allowed to "merge" the two objects, for any reason. I know that Java and C#, which implement reference-semantics (not value-semantics) can do certain crazy things of that nature (but I don't think it would do that particular example-case, because it makes no sense at all).

Even in this case:

struct B{
  const int v=100;
  virtual int get_derived_value()=0;
};
struct D1:B{
  int v1;
  int get_derived_value(){return v1;}
  D1():v1(1000){}
};

void myfct(){
  D1 d1;
  D1 d2 = d1;
  B* bp1=&d1;
  B* bp2=&d2;
  if (bp1==bp2){
    //this code will NEVER execute, the compiler will not implement "copy-on-write" because C++ has value-semantics!
  }
}

In the above case, as before, the compiler could by-pass the virtual dispatch, but the conditional will never evaluate to true. If you want copy-on-write mechanisms in C++, you have to implement them yourself, the compiler does not do that under any circumstance... C++ is not Java.

You say: "a smart compiler could optimise this by seeing that the next lines (below) of this function never use the derived part of d1 and d2 and that the base part has an identical content"

No it can't. The only way a compiler could do so would be if the program's behavior didn't change. But the moment you make your program depend in any way on d1 and d2 having different addresses, putting d1 and d2 in the same place would change the program's behavior. So that's not an acceptable optimization.

Different objects have different addresses.

Many thanks Mike, I think you have anwered my question. Just to be sure I understand correctly could you just confirmed in the following case (which is in fact my application) I shall not fear any optimisation surprise?
My code involve keeping an array of base pointers to a variety of derived object.
I just want to be sure that when 2 base pointers in that array are identical (as compared with ==), I am 100% guaranteed that they will be pointing to identical derived object, and that there can never be a case of those 2 pointers pointing to an identical base part of 2 different derived object created by fancy compiler optimisation.

>>I shall not fear any optimisation surprise?

Do not fear. You are 100% guaranteed that if you have two base pointers which are identical (same address), then they point to the same object. And when I say 100%, I don't mean 99.999%, I mean 100%.

What you might/could/should fear, depending on the complexity of your class hierarchy, is the opposite case. That is, if you use multiple inheritance and don't use also virtual inheritance, you could have the problem that two base pointers which are different actual point to the same object. Read this to know why.

This solves my problem.
Many thanks again Mike.
(I trust you because you are an aerospace engineer, and CNN hasn't reported (as far as I know) any plane crashing because of a base pointer unexpected optimisation.... ;-) )

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.