473,473 Members | 1,707 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

strange multi-inheritance problem


First, I know the following code is bad, but it's from a library I have
to use, and I can't change it.

class A {
// some primitive members
};

class B {
// some primitive members
};

class C : public A, B {
// no members
};

main() {
// I know sizeof(A) = 16, sizeof(B) = 60
C * pc = (C*) new char[sizeof(A) + sizeof(B)];
B * pb = (B*) pc;

char * p1 = (char *) pc;
char * p2 = (char *) pb;

cout << "offset : " << (p2 - p1) << endl;
}

What surprised me is that the offset is 20 instead of 16. Do you know
the possible reason?

Regards.

Sep 20 '05 #1
13 1458
Also it turns out that sizeof(C) = 80.

Sep 20 '05 #2
"Patricia" <la******@gmail.com> wrote in message
news:11**********************@o13g2000cwo.googlegr oups.com...

First, I know the following code is bad, but it's from a library I have
to use, and I can't change it.

class A {
// some primitive members
};

class B {
// some primitive members
};

class C : public A, B {
// no members
};

main() {
The return type of main must be explicitly specified as int:

int main() {
// I know sizeof(A) = 16, sizeof(B) = 60
Do you also know sizeof(C)?
C * pc = (C*) new char[sizeof(A) + sizeof(B)];
That is undefined behavior. You cannot assume that sizeof(C) will be equal
to sizeof(A) and sizeof(B). Nor can you assume that there is a C object
there. Those are just a bunch of uninitialized characters. You cannot assume
that they can be readily used as a C.
B * pb = (B*) pc;
Actually, C inherits from B privately. You can't assume that the C-style
cast above will give you access to the B part a C. If you intended to
inherit publicly from C, then the cast is not needed:

B * pb = pc;
char * p1 = (char *) pc;
char * p2 = (char *) pb;

cout << "offset : " << (p2 - p1) << endl;
}

What surprised me is that the offset is 20 instead of 16. Do you know
the possible reason?


The reason is that the program's behavior is undefined.

As a side note, you should abandon using the C-style casts. Use one of C++'s
casting operators to make it explicit what you're saying, and to get help
from the compiler when the casting is illegal.

Ali

Sep 20 '05 #3
"Patricia" <la******@gmail.com> wrote in message
news:11**********************@o13g2000cwo.googlegr oups.com...

First, I know the following code is bad, but it's from a library I have
to use, and I can't change it.

class A {
// some primitive members
};

class B {
// some primitive members
};

class C : public A, B {
// no members
};

main() {
// I know sizeof(A) = 16, sizeof(B) = 60
C * pc = (C*) new char[sizeof(A) + sizeof(B)];
B * pb = (B*) pc;

char * p1 = (char *) pc;
char * p2 = (char *) pb;

cout << "offset : " << (p2 - p1) << endl;
}

What surprised me is that the offset is 20 instead of 16. Do you know
the possible reason?


The following is a better way of doing what you are trying to do:

#include <iostream>
#include <memory>

class A {
// some primitive members
int a[4];
};

class B {
// some primitive members
int a[15];
};

class C : public A, public B {
// no members
};

int main() {
std::cout << " sizeof(A): " << sizeof(A)
<< " sizeof(B): " << sizeof(B)
<< " sizeof(C): " << sizeof(C)
<< '\n';

// Allocate a buffer
char * buffer = new char[sizeof(C)];

// Use placement new to construct an object on that buffer
C * pc = new (reinterpret_cast<void *>(buffer)) C();

// A valid up-cast
B * pb = pc;

char * p1 = reinterpret_cast<char *>(pc);
char * p2 = reinterpret_cast<char *>(pb);

// WARNING: Undefined behavior below! We cannot subtract two
// pointers unless they point to objects of the same
// array. Nevertheless, the results may be useful on a given system.
std::cout << "offset : " << (p2 - p1) << endl;

// Destroy the C object manually and release the buffer
pc->~C();
delete buffer;
}

Ali

Sep 20 '05 #4
"Ali Çehreli" <ac******@yahoo.com> wrote in message
news:dg**********@domitilla.aioe.org...
// Allocate a buffer
char * buffer = new char[sizeof(C)];

// Use placement new to construct an object on that buffer
C * pc = new (reinterpret_cast<void *>(buffer)) C();
[...]
// Destroy the C object manually and release the buffer
pc->~C();
delete buffer;
}


And that would be a bug of course. :) Should be:

delete[] buffer;

Ali

Sep 20 '05 #5
Sorry, I just want to give a rough idea of the problem. As I said, I
have to use the old library, and can't change it. The old library
should look like below.

class C : public A, public B {
// no members
};

main() {
// sizeof(A) = 16, sizeof(B) = 60, but sizeof(C) = 80
C * pc = (C*) new char[sizeof(A) + sizeof(B)];
new (pc) C();
B * pb = (B*) pc;

char * p1 = (char *) pc;
char * p2 = (char *) pb;

cout << "offset : " << (p2 - p1) << endl;

delete [] (char *)pc;
}

It's strange that sizeof(C) > sizeof(A) + sizeof(B). The thing is when
I declare my own A, B, C classes, it turns out sizeof(C) = sizeof(A) +
sizeof(B).

Is it because of a compiler option. By the way, I compile the program
with CC on Solaris 8.

Sep 20 '05 #6
"Patricia" <la******@gmail.com> wrote in message
news:11**********************@o13g2000cwo.googlegr oups.com...
class C : public A, public B {
// no members
};

main() {
// sizeof(A) = 16, sizeof(B) = 60, but sizeof(C) = 80
C * pc = (C*) new char[sizeof(A) + sizeof(B)];
That is plain wrong. You can fit a C only on an area that has the size of at
least sizeof(C). Please use placement new to construct a C on a
pre-allocated memory. (I've already posted an example of this on this
thread.)
It's strange that sizeof(C) > sizeof(A) + sizeof(B).


The compiler is free use padding bytes between parts of objects.

Ali

Sep 20 '05 #7
Sorry, the above code is simplified. The real situation is there is a
class D which derives from B. Although C derives from A and B, they
used a memory block to hold A and D as below:

C * pc = (C*) new char[sizeof(A) + sizeof(D)];
new (pc) C();
B * pb = (B*) pc;

char * p1 = (char *) pc;
char * p2 = (char *) pb;

cout << "offset : " << (p2 - p1) << endl;

The code looks weird, but this is the real implemenation which was
written between 1995 and 1999.

Since A's size is 16, I don't know why the offset is 20.

Sep 20 '05 #8
Patricia wrote:
First, I know the following code is bad, but it's from a library I have
to use, and I can't change it.

class A {
// some primitive members
};

class B {
// some primitive members
};

class C : public A, B {
// no members
};

main() {
// I know sizeof(A) = 16, sizeof(B) = 60
C * pc = (C*) new char[sizeof(A) + sizeof(B)];
B * pb = (B*) pc;

char * p1 = (char *) pc;
char * p2 = (char *) pb;

cout << "offset : " << (p2 - p1) << endl;
}

What surprised me is that the offset is 20 instead of 16. Do you know
the possible reason?


The compiler has adding padding between the A part of C and the B part of C.

Object C is

16 bytes of A
4 bytes of padding
60 bytes of B

Compilers are allowed to do this, which is why you should not assume
that sizeof(C) = sizeof(A) + sizeof(B)

john
Sep 20 '05 #9
Ali Çehreli wrote:
char * buffer = new char[sizeof(C)];

C * pc = new (reinterpret_cast<void *>(buffer)) C();
B * pb = pc;
char * p1 = reinterpret_cast<char *>(pc);
char * p2 = reinterpret_cast<char *>(pb);

// WARNING: Undefined behavior below! We cannot subtract two
// pointers unless they point to objects of the same
// array. Nevertheless, the results may be useful on a given system.
std::cout << "offset : " << (p2 - p1) << endl;


p1 and p2 both point to within the object 'buffer' points to,
so I think the behaviour is defined.

Sep 20 '05 #10
Old Wolf wrote:
Ali Çehreli wrote:
char * buffer = new char[sizeof(C)];

C * pc = new (reinterpret_cast<void *>(buffer)) C();
B * pb = pc;
char * p1 = reinterpret_cast<char *>(pc);
char * p2 = reinterpret_cast<char *>(pb);

// WARNING: Undefined behavior below! We cannot subtract two
// pointers unless they point to objects of the same
// array. Nevertheless, the results may be useful on a given system.
std::cout << "offset : " << (p2 - p1) << endl;

p1 and p2 both point to within the object 'buffer' points to,
so I think the behaviour is defined.


However, there's no need for reinterpret_cast. Assuming that p1 and p2
point into the same object, use

void *p1 = static_cast<void*>(pc);
void *p2 = static_cast<void*>(pb);
std::cout << (p2 - p1) << std::endl;
Sep 21 '05 #11
"red floyd" <no*****@here.dude> wrote in message
news:ke*****************@newssvr14.news.prodigy.co m...
Old Wolf wrote:
Ali Çehreli wrote:
char * buffer = new char[sizeof(C)];

C * pc = new (reinterpret_cast<void *>(buffer)) C();
B * pb = pc;
char * p1 = reinterpret_cast<char *>(pc);
char * p2 = reinterpret_cast<char *>(pb);

// WARNING: Undefined behavior below! We cannot subtract two
// pointers unless they point to objects of the same
// array. Nevertheless, the results may be useful on a given system.
std::cout << "offset : " << (p2 - p1) << endl;

p1 and p2 both point to within the object 'buffer' points to,
so I think the behaviour is defined.


However, there's no need for reinterpret_cast. Assuming that p1 and p2
point into the same object, use

void *p1 = static_cast<void*>(pc);
void *p2 = static_cast<void*>(pb);
std::cout << (p2 - p1) << std::endl;


Unfortunately that won't work :( Cannot do pointer arithmetic on void*
types.

Ali

Sep 21 '05 #12
> The compiler has adding padding between the A part of C and the B part of C.

Object C is

16 bytes of A
4 bytes of padding
60 bytes of B

Compilers are allowed to do this, which is why you should not assume
that sizeof(C) = sizeof(A) + sizeof(B)


It seems the compiler tries to make the size of a class dividable by 8.

The thing is the library behaves as mentioned above, but the same
compiler does not add padding for my own test code. I guess sizeof is
calcuated at compile time. Is it common or possible for the same
compiler behaves differently for different code ?

Sep 21 '05 #13

John Harrison wrote:
Patricia wrote:
First, I know the following code is bad, but it's from a library I have
to use, and I can't change it.

class A {
// some primitive members
};

class B {
// some primitive members
};

class C : public A, B {
// no members
};

main() {
// I know sizeof(A) = 16, sizeof(B) = 60
C * pc = (C*) new char[sizeof(A) + sizeof(B)];
B * pb = (B*) pc;

char * p1 = (char *) pc;
char * p2 = (char *) pb;

cout << "offset : " << (p2 - p1) << endl;
}

What surprised me is that the offset is 20 instead of 16. Do you know
the possible reason?


The compiler has adding padding between the A part of C and the B part of C.

Object C is

16 bytes of A
4 bytes of padding
60 bytes of B

Compilers are allowed to do this, which is why you should not assume
that sizeof(C) = sizeof(A) + sizeof(B)

john


This really sounds strange from a pragmatic point of view. I would
rather expect that the C object is structured like:

60 bytes of B
4 bytes of padding
16 bytes of A

I am unsure if the compiler is allowed to store the objects in that
way, but if not the more likely situation is that C was declared as
public B, public A.

/Peter

Sep 21 '05 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

37
by: ajikoe | last post by:
Hello, Is anyone has experiance in running python code to run multi thread parallel in multi processor. Is it possible ? Can python manage which cpu shoud do every thread? Sincerely Yours,...
12
by: * ProteanThread * | last post by:
but depends upon the clique: ...
0
by: NoSpammer | last post by:
Hi All, I'm building a server-clients app that will send/receive files, using socket listener and client sockets. During test, I found that: 1. if sender and receiver on different machine (or...
6
by: cody | last post by:
What are multi file assemblies good for? What are the advantages of using multiple assemblies (A.DLL+B.DLL) vs. a single multi file assembly (A.DLL+A.NETMODULE)?
0
by: Hai Ly Hoang | last post by:
Hi, I'm using VC++ 7.0 (VS 2003). My code: void main() { int *a = new int; } I'm sure that the above code is accepted by VC++ (no compiling error). What is exactly the semantic of the above...
5
by: bobwansink | last post by:
Hi, I'm relatively new to programming and I would like to create a C++ multi user program. It's for a project for school. This means I will have to write a paper about the theory too. Does anyone...
0
by: cgambino | last post by:
Hello all, I have a Microsoft VB.NET 2.0 windows service that throws a strange error a few seconds after the service logs the "Service stopped successfully" message. I was wondering if anyone...
0
by: Sabri.Pllana | last post by:
We apologize if you receive multiple copies of this call for papers. *********************************************************************** 2008 International Workshop on Multi-Core Computing...
1
by: mknoll217 | last post by:
I am recieving this error from my code: The multi-part identifier "PAR.UniqueID" could not be bound. The multi-part identifier "Salary.UniqueID" could not be bound. The multi-part identifier...
16
by: Heinrich Pumpernickel | last post by:
i got the following strange extra question in a written test today . since the test was abt c/c++ i guess this is on topic here --8<-- 22) Consider the following quote: "If Mickey's a...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.