C++ overwriting data from parent structure is not working - c++

Normally it has no sense and is very unsafe, but only theoretically if there is a way,
Here is example:
#include<iostream>
struct A {
uint32_t &get() {
return *reinterpret_cast<uint32_t *>(this);
}
void set(const uint32_t val) {
*this = *reinterpret_cast<const A *>(&val);
}
};
struct B : A {
uint16_t a;
uint16_t b;
void set_b(const uint32_t val) {
*this = *reinterpret_cast<const B *>(&val);
}
};
main() {
B k;
k.a = 0x1234;
k.b = 0x5678;
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
k.set_b(0x87654321);
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
k.set(0xaabbccdd);
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
}
I get this result:
56781234 : 1234 5678
87654321 : 4321 8765
87654321 : 4321 8765
But I except that last should be:
aabbccdd : ccdd aabb
So, why overwriting data in structure from parent not working?
Experiment:
I make one experiment, that I add one variable into struct A, then set function was working as expected (but final structure was bigger)
Of course there exists different ways how to deal with this (for example with unions) but I only playing with this and I interested why this is not working.

In the class A the set function is really
void set(const uint32_t val) {
(*this).operator=(*reinterpret_cast<const A *>(&val));
}
That will invoke the automatically generated A::operator= function. But since A doesn't have any member variables to be copied, it does nothing.
And now that you've done your experiment, please don't do anything like that ever again.

Related

Proper handling of member function pointers

I wrote a generic class for handling and executing a function pointer. This is a simplified equivalent of std::function and std::bind. To handle member functions I use cast to internal EventHandler::Class type. Question: is it ok to cast it that way? Will it work in all cases when invoking handled function?
template <typename ReturnType, typename... Arguments>
class EventHandler
{
class Class {};
ReturnType (Class::*memberFunction)(Arguments...) = nullptr;
union {
Class *owner;
ReturnType(*function)(Arguments...) = nullptr;
};
public:
EventHandler() = default;
EventHandler(EventHandler &&) = default;
EventHandler(const EventHandler &) = default;
EventHandler &operator=(EventHandler &&) = default;
EventHandler &operator=(const EventHandler &) = default;
EventHandler(ReturnType (*function)(Arguments...)) :
function(function)
{
}
template <typename Owner>
EventHandler(Owner *owner, ReturnType (Owner::*memberFunction)(Arguments...)) :
memberFunction((ReturnType (Class::*)(Arguments...)) memberFunction),
owner((Class *) owner)
{
}
template <typename Owner>
EventHandler(const Owner *owner, ReturnType (Owner::*memberFunction)(Arguments...) const) :
memberFunction((ReturnType (Class::*)(Arguments...)) memberFunction),
owner((Class *) owner)
{
}
ReturnType operator()(Arguments... arguments)
{
return memberFunction ?
(owner ? (owner->*memberFunction)(arguments...) : ReturnType()) :
(function ? function(arguments...) : ReturnType());
}
};
The implementation provides handle for a global function, a member function and a const member function. Obviously there is volatile and const volatile that is not show here for clarity.
EDIT
All the code below is just a representation of all of kinds of supported functions.
class Object
{
public:
double y = 1000;
Object() = default;
Object(double y) : y(y) {}
static void s1(void) { std::cout << "s1()" << std::endl; }
static void s2(int a) { std::cout << "s2(a:" << 10 + a << ")" << std::endl; }
static void s3(int a, float b) { std::cout << "s3(a:" << 10 + a << ", b:" << 10 + b << ")" << std::endl; }
static int s4(void) { std::cout << "s4(): "; return 10 + 4; }
static Object s5(int a) { std::cout << "s5(a:" << 10 + a << "): "; return Object(10 + 5.1); }
static float s6(int a, Object b) { std::cout << "s6(a:" << 10 + a << ", b:" << 10 + b.y << "); "; return 10 + 6.2f; }
void m1(void) { std::cout << "m1()" << std::endl; }
void m2(int a) { std::cout << "m2(a:" << y + a << ")" << std::endl; }
void m3(int a, float b) { std::cout << "m3(a:" << y + a << ", b:" << y + b << ")" << std::endl; }
int m4(void) { std::cout << "m4(): "; return ((int) y) + 4; }
Object m5(int a) { std::cout << "m5(a:" << y + a << "): "; return Object(y + 5.1); }
float m6(int a, Object b) { std::cout << "m6(a:" << y + a << ", b:" << y + b.y << "); "; return ((int) y) + 6.2f; }
void c1(void) const { std::cout << "c1()" << std::endl; }
void c2(int a) const { std::cout << "c2(a:" << y + a << ")" << std::endl; }
void c3(int a, float b) const { std::cout << "c3(a:" << y + a << ", b:" << y + b << ")" << std::endl; }
int c4(void) const { std::cout << "c4(): "; return ((int) y) + 4; }
Object c5(int a) const { std::cout << "c5(a:" << y + a << "): "; return Object(y + 5.1); }
float c6(int a, Object b) const { std::cout << "c6(a:" << y + a << ", b:" << y + b.y << "); "; return ((int) y) + 6.2f; }
};
void f1(void) { std::cout << "f1()" << std::endl; }
void f2(int a) { std::cout << "f2(a:" << a << ")" << std::endl; }
void f3(int a, float b) { std::cout << "f3(a:" << a << ", b:" << b << ")" << std::endl; }
int f4(void) { std::cout << "f4(): "; return 4; }
Object f5(int a) { std::cout << "f5(a:" << a << "): "; return Object(5.1); }
float f6(int a, Object b) { std::cout << "f6(a:" << a << ", b:" << b.y << "); "; return 6.2f; }
Here is the usage example for all of the above functions
int main()
{
std::cout << "=== Global functions" << std::endl;
EventHandler ef1(f1); ef1();
EventHandler ef2(f2); ef2(2);
EventHandler ef3(f3); ef3(3, 3.1f);
EventHandler ef4(f4); std::cout << ef4() << std::endl;
EventHandler ef5(f5); std::cout << ef5(5).y << std::endl;
EventHandler ef6(f6); std::cout << ef6(6, Object(6.1)) << std::endl;
std::cout << std::endl;
std::cout << "=== Member static functions" << std::endl;
EventHandler es1(Object::s1); es1();
EventHandler es2(Object::s2); es2(2);
EventHandler es3(Object::s3); es3(3, 3.1f);
EventHandler es4(Object::s4); std::cout << es4() << std::endl;
EventHandler es5(Object::s5); std::cout << es5(5).y << std::endl;
EventHandler es6(Object::s6); std::cout << es6(6, Object(6.1)) << std::endl;
std::cout << std::endl;
std::cout << "=== Member functions" << std::endl;
Object object(20);
EventHandler em1(&object, &Object::m1); em1();
EventHandler em2(&object, &Object::m2); em2(2);
EventHandler em3(&object, &Object::m3); em3(3, 3.1f);
EventHandler em4(&object, &Object::m4); std::cout << em4() << std::endl;
EventHandler em5(&object, &Object::m5); std::cout << em5(5).y << std::endl;
EventHandler em6(&object, &Object::m6); std::cout << em6(6, Object(6.1)) << std::endl;
std::cout << std::endl;
std::cout << "=== Member const functions" << std::endl;
const Object constObject(30);
EventHandler ec1(&constObject, &Object::c1); ec1();
EventHandler ec2(&constObject, &Object::c2); ec2(2);
EventHandler ec3(&constObject, &Object::c3); ec3(3, 3.1f);
EventHandler ec4(&constObject, &Object::c4); std::cout << ec4() << std::endl;
EventHandler ec5(&constObject, &Object::c5); std::cout << ec5(5).y << std::endl;
EventHandler ec6(&constObject, &Object::c6); std::cout << ec6(6, Object(6.1)) << std::endl;
system("pause");
return 0;
}
Finally - to the point - here an example that shows how much easier in use is the EventHandler I prepared when compared to std::function interface. And actually the reason of such approach.
EventHandler<float, int, Object> example;
example = f6;
example(7, Object(7.1));
example = EventHandler(&object, &Object::m6);;
example(8, Object(8.1));
It’s undefined behavior to call a function through a function pointer(-to-member) of a different type. (Some practical reasons for this rule are that the object’s address might need to be adjusted to call a member function of a base class or that a vtable might be involved.) You can use type erasure to allow calling member functions on objects of different types (which is what std::bind does), or you can (restrict to member functions and) add the class type as a template parameter.
Of course, the usual answer is to just use std::function with a lambda that captures the object in question and calls whatever member function. You can also take the C approach and define various functions with a void* parameter that cast that parameter to a known class type and call the desired member function.

How change class of a C++ object (implementing a variadic type)

First off: I know that it is generally a bad idea to change an object's class, but I'm implementing my own programming language, and it has variables that can contain values of any type, and even change their type at will, so please assume I'm not a beginner not understanding OO basics.
Currently, I implement my variant variables in C. Each one has a pointer to a table of function pointers, containing functions like SetAsInt(), SetAsString() etc., followed by what would be instance variables in C++. All objects are the same size.
When a variable contains a string and someone assigns an Int to it, I manually call the destructor, change the table of function pointers to point to the table used for variadic int values, and then set its int instance variable.
This is a bit hard to maintain, as every time I add a new type, I have to add a new table of function pointers and fill out all the function pointers in it. Structs of function pointers seem to be very badly type-checked, and missing fields don't lead to complaints, so I can easily accidentally forget one pointer in the list and get interesting crashes. Also, I have to repeat all the function pointers that are the same in most types.
I'd like to implement my variadic types in C++ instead, where a lot of this type-checking and inheriting default behaviours is done for me by the compiler. Is there a safe way to do this?
PS - I know I could create a wrapper object and use new to allocate a new object, but I can't have the additional extra allocation overhead for every int variable on the stack.
PPS - The code needs to be portable across Linux, Mac, iOS and Windows for now, but if someone has a standard C++ solution, that would be even better.
PPPS - The list of types is extensible, but predetermined at compile-time. The base layer of my language defines just the basic types, but the host application my language is compiled into adds a few more types.
Usage Example:
CppVariant someNum(42); // Creates it as CppVariantInt.
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This calls destructor on CppVariantInt and constructor on CppVariantDouble(12.34).
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl; // GetAsInt() on a CppVariantDouble() rounds, or whatever.
(Imagine that beyond double and int, there would be other types in the future, like strings or booleans, but the caller of GetAsInt()/SetAsInt() shouldn't have to know what it is stored as, as long as it can be converted at runtime)
Here is a solution based on type-erasure, union and template specializations.
I'm not sure it fits your requirements.
Anyway, here is what it gets:
Anything is placed on the dynamic storage
No hierarchy required
You can easily improve it further to reduce the amount of code, but this aims to serve as a base point from which to start.
It follows a minimal, working example based on the intended use in the question:
#include<iostream>
class CppVariant {
union var {
var(): i{0} {}
int i;
double d;
};
using AsIntF = int(*)(var);
using AsDoubleF = double(*)(var);
template<typename From, typename To>
static To protoAs(var);
public:
CppVariant(int);
CppVariant(double);
int getAsInt();
double getAsDouble();
void setAsInt(int);
void setAsDouble(double);
private:
var data;
AsIntF asInt;
AsDoubleF asDouble;
};
template<>
int CppVariant::protoAs<int, int>(var data) {
return data.i;
}
template<>
int CppVariant::protoAs<double, int>(var data) {
return int(data.d);
}
template<>
double CppVariant::protoAs<int, double>(var data) {
return double(data.i);
}
template<>
double CppVariant::protoAs<double, double>(var data) {
return data.d;
}
CppVariant::CppVariant(int i)
: data{},
asInt{&protoAs<int, int>},
asDouble{&protoAs<int, double>}
{ data.i = i; }
CppVariant::CppVariant(double d)
: data{},
asInt{&protoAs<double, int>},
asDouble{&protoAs<double, double>}
{ data.d = d; }
int CppVariant::getAsInt() { return asInt(data); }
double CppVariant::getAsDouble() { return asDouble(data); }
void CppVariant::setAsInt(int i) {
data.i = i;
asInt = &protoAs<int, int>;
asDouble = &protoAs<int, double>;
}
void CppVariant::setAsDouble(double d) {
data.d = d;
asInt = &protoAs<double, int>;
asDouble = &protoAs<double, double>;
}
int main() {
CppVariant someNum(42);
std::cout << "Original int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsInt(700);
std::cout << "Changed int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsDouble(12.34);
std::cout << "Converted to Double: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
}
On a lark, I tried using placement new to do this, and I have ... something ... It compiles, it does the job, but I'm not sure if it's an improvement over pure C. Since I can't have a union of C++ objects, I create a CPPVMAX() macro to pass the largest sizeof() of all subclasses as the size to mBuf[], but that's not really pretty either.
#include <iostream>
#include <string>
#include <cmath>
#define CPPVMAX2(a,b) (((a) > (b)) ? (a) : (b))
#define CPPVMAX3(a,b,c) CPPVMAX2((a),CPPVMAX2((b),(c)))
using namespace std;
class CppVariantBase
{
public:
CppVariantBase() { cout << "CppVariantBase constructor." << endl; }
virtual ~CppVariantBase() { cout << "CppVariantBase destructor." << endl; }
virtual int GetAsInt() = 0;
virtual double GetAsDouble() = 0;
virtual void SetAsInt( int n );
virtual void SetAsDouble( double n );
};
class CppVariantInt : public CppVariantBase
{
public:
CppVariantInt( int n = 0 ) : mInt(n)
{
cout << "CppVariantInt constructor." << endl;
}
~CppVariantInt() { cout << "CppVariantInt destructor." << endl; }
virtual int GetAsInt() { return mInt; }
virtual double GetAsDouble() { return mInt; }
virtual void SetAsInt( int n ) { mInt = n; }
protected:
int mInt;
};
class CppVariantDouble : public CppVariantBase
{
public:
CppVariantDouble( double n = 0 ) : mDouble(n)
{
cout << "CppVariantDouble constructor." << endl;
}
~CppVariantDouble()
{
cout << "CppVariantDouble destructor." << endl;
}
virtual int GetAsInt()
{
if( int(mDouble) == mDouble )
return mDouble;
else
return round(mDouble);
}
virtual double GetAsDouble() { return mDouble; }
virtual void SetAsDouble( int n ) { mDouble = n; }
protected:
double mDouble;
};
class CppVariant
{
public:
CppVariant( int n = 0 ) { new (mBuf) CppVariantInt(n); }
~CppVariant() { ((CppVariantBase*)mBuf)->~CppVariantBase(); }
operator CppVariantBase* () { return (CppVariantBase*)mBuf; }
CppVariantBase* operator -> () { return (CppVariantBase*)mBuf; }
protected:
uint8_t mBuf[CPPVMAX3(sizeof(CppVariantBase),sizeof(CppVariantInt),sizeof(CppVariantDouble))];
};
void CppVariantBase::SetAsInt( int n )
{
this->~CppVariantBase();
new (this) CppVariantInt(n);
}
void CppVariantBase::SetAsDouble( double n )
{
this->~CppVariantBase();
new (this) CppVariantDouble(n);
}
int main(int argc, const char * argv[]) {
CppVariant someNum(42);
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This changes the class to CppVariantDouble.
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
return 0;
}

Virtual inheritance and polymorphism: Is the cereal library messing with object layout?

I have four classes (A,B,C and D) following the classic diamond pattern and a Container class containing a unique_ptr<A>. I want to serialize these classes using the cereal serialization library.
struct A {int f1; int f2; int f3}
struct B : public virtual A {
template<typename Archive>
inline void save(Archive& ar) const {
std::cerr << "Saving Obj: " << this << std::endl;
std::cerr << "This: " << &(this->f1) << " "
<< &(this->f2) << " " << &(this->f3) << std::endl;
std::cerr << "This: " << this->f1 << " "
<< this->f2 << " " << this->f3 << std::endl;
};
}
};
struct C : public virtual A {};
struct D : public B, public C {};
#include <cereal/archives/binary.hpp>
CEREAL_REGISTER_TYPE(B);
CEREAL_REGISTER_TYPE(C);
CEREAL_REGISTER_TYPE(D);
struct Container {
std::unique_ptr<A> obj;
template<typename Archive>
inline void save(Archive& ar) const {
std::cerr << "Saving Container" << std::endl;
std::cerr << "Obj Addr: " << obj.get() << std::endl;
std::cerr << "Obj: " << &(obj->f1) << " " << &(obj->f2)
<< " " << &(pq->f3) << std::endl;
std::cerr << "Obj: " << " " << pq->sq_count << " " << pq->sq_bits
<< " " << pq->dim << std::endl;
ar(obj); // Call serialization for obj, ie B.save(...)
}
}
All classes have cereal save and load functions, but I only included them for B and Container, as they are the only ones used in this example.
I use these classes as follows :
std::unique_ptr<A> obj(new B);
obj->f1 = 8;
obj->f2 = 8;
obj->f3 = 128;
std::unique_ptr<Container> db(new Container);
db.obj = std::move(obj);
std::ofstream out_file(out_filename);
cereal::BinaryOutputArchive out_archive(out_file);
out_archive(db);
And I get the following output:
Saving Container
Obj Addr: 0x23d2128
Obj: 0x23d2130 0x23d2134 0x23d2138 // Fields adresses (f1,f2,f3)
Obj: 8 8 128 // Fields values
Saving Obj: 0x23d2128 // Same object
This: 0x23d2118 0x23d211c 0x23d2120 // Different field adresses !
This: 4293296 0 37569440 // Garbage
My question is: Is it likely that this is a bug in cereal, or is there something that I don't get with virtual inheritance ?
Is it expected that the addresses of the fields of a given object ever change in a C++ program ?
I can't reproduce your error on the current develop branch of cereal, however I can reproduce it on the current master (1.1.2). I modified your code to actually compile:
#include <cereal/types/memory.hpp>
#include <cereal/types/polymorphic.hpp>
#include <cereal/archives/json.hpp>
#include <fstream>
#include <iostream>
struct A {
int f1; int f2; int f3;
virtual ~A() {}
template<typename Archive>
void serialize( Archive & ar )
{
std::cerr << "Saving A Obj: " << this << std::endl;
std::cerr << "This: " << &(this->f1) << " "
<< &(this->f2) << " " << &(this->f3) << std::endl;
std::cerr << "This: " << this->f1 << " "
<< this->f2 << " " << this->f3 << std::endl;
};
};
struct B : public virtual A {
template <class Archive>
void serialize( Archive & ar )
{
std::cerr << "Saving B Obj: " << this << std::endl;
std::cerr << "This: " << &(this->f1) << " "
<< &(this->f2) << " " << &(this->f3) << std::endl;
std::cerr << "This: " << this->f1 << " "
<< this->f2 << " " << this->f3 << std::endl;
ar( cereal::virtual_base_class<A>( this ) );
}
virtual ~B() {}
};
CEREAL_REGISTER_TYPE(B);
struct Container {
std::unique_ptr<A> obj;
template<typename Archive>
void serialize( Archive & ar )
{
std::cerr << "Saving Container (A)" << std::endl;
std::cerr << "Obj Addr: " << obj.get() << std::endl;
std::cerr << "Obj: " << &(obj->f1) << " " << &(obj->f2)
<< " " << &(obj->f3) << std::endl;
ar(obj); // Call serialization for obj, ie B.save(...)
}
};
int main()
{
std::unique_ptr<A> ptr(new B());
ptr->f1 = 8;
ptr->f2 = 8;
ptr->f3 = 128;
std::unique_ptr<Container> db(new Container());
db->obj = std::move(ptr);
std::stringstream ss;
{
cereal::JSONOutputArchive out_archive(ss);
out_archive(db);
}
std::cout << ss.str() << std::endl;
}
The output with 1.1.2:
Saving Container (A)
Obj Addr: 0x1738d78
Obj: 0x1738d80 0x1738d84 0x1738d88
Saving B Obj: 0x1738d78
This: 0x1738d78 0x1738d7c 0x1738d80
This: 4316664 0 8
Saving A Obj: 0x1738d70
This: 0x1738d78 0x1738d7c 0x1738d80
This: 4316664 0 8
{
"value0": {
"ptr_wrapper": {
"valid": 1,
"data": {
"value0": {
"polymorphic_id": 2147483649,
"polymorphic_name": "B",
"ptr_wrapper": {
"valid": 1,
"data": {
"value0": {}
}
}
}
}
}
}
}
The output using develop:
Saving Container (A)
Obj Addr: 0x1f74e18
Obj: 0x1f74e20 0x1f74e24 0x1f74e28
Saving B Obj: 0x1f74e10
This: 0x1f74e20 0x1f74e24 0x1f74e28
This: 8 8 128
Saving A Obj: 0x1f74e18
This: 0x1f74e20 0x1f74e24 0x1f74e28
This: 8 8 128
{
"value0": {
"ptr_wrapper": {
"valid": 1,
"data": {
"value0": {
"polymorphic_id": 2147483649,
"polymorphic_name": "B",
"ptr_wrapper": {
"valid": 1,
"data": {
"value0": {}
}
}
}
}
}
}
}
So whatever was causing this problem is likely fixed in the current develop branch of cereal, which will be released as 1.2 in the near future.

Why Would reinterpret_cast<const char*> of a Class and of Its Pre-Initialized Member Int Be the Same While Any Other Type of Variable Isnt?

I got this from an online exam (http://www.interqiew.com/tests?type=cpp) and have been stumped for some time.
I just don't get it. It compiles and runs fine. I've modified the code to be more expressive of the weirdness.
CODE:
#include <cstddef>
#include <iostream>
class A{
public:
A( ) : m_x( 3 ) { };
static ptrdiff_t member_offsetA(const A &a){
const char *p = reinterpret_cast<const char*>(&a);
const char *q = reinterpret_cast<const char*>(&a.m_x);
const char *z = reinterpret_cast<const char*>(&a.m_y);
const char *s = reinterpret_cast<const char*>(&a.m_s);
std::cout << q << " VS " << p << " VS " << z << " VS " << s << std::endl << std::endl;
return p-q;
}
static ptrdiff_t member_offsetB(const A &a){
const char *p = reinterpret_cast<const char*>(&a);
const char *q = reinterpret_cast<const char*>(&a.m_x);
const char *z = reinterpret_cast<const char*>(&a.m_y);
const char *s = reinterpret_cast<const char*>(&a.m_s);
std::cout << q << " VS " << p << " VS " << z << " VS " << s << std::endl << std::endl;
return z-s;
}
static ptrdiff_t member_offsetC(const A &a){
const char *p = reinterpret_cast<const char*>(&a);
const char *q = reinterpret_cast<const char*>(&a.m_x);
const char *z = reinterpret_cast<const char*>(&a.m_c);
std::cout << q << " VS " << q << std::endl << " VS " << z << std::endl;
return q-z;
}
private:
int m_x;
int m_c;
char m_y;
std::string m_s;
};
int main(){
A a;
std::cout << ( ( A::member_offsetA( a ) == 0 ) ? 0 : 1 ) << std::endl;
std::cout << ( ( A::member_offsetB( a ) == 0 ) ? 2 : 3 ) << std::endl;
std::cout << ( ( A::member_offsetC( a ) == 0 ) ? 4 : 5 ) << std::endl;
return 0;
}
OUTPUT: Symbols will be represented by unique letters preceded by three X's. So all XXXS's represent the same symbol. Whitespace means nothing was printed there.
XXXA VS XXXA VS VS XXXB
0
XXXA VS XXXA VS VS XXXB
3
XXXA VS XXXA
VS XXXF
5
How does any of this make sense?
Why would the casting for a class and a member int produce the same results? Wouldn't they be different? If they're the same, why would other member values be different?
Also, why would anyone ever use this?
P.S. Paste of actual output:
VS VS �# VS �����
0
VS VS �# VS �����
3
VS
VS �
5
I don't see anything strange here. It makes perfect sense.
For normal, non-polymorphic classes the address of an instance of a class will be the same as the address of the first member of that class. That's just what an instance of a class is; it's the sum of all its members laid out sequentially (the instance itself adds nothing, unless it's a polymorphic class, or has non-empty base classes.) This is (not exactly but almost) called an "standard-layout" class in C++ (Note: the actual definition is obviously more complex.)
In the case of the members inside a class (and in fact for all variables,) no two of them can have the same address. And in fact they need 1 or more bytes of memory (you know, to store the bits of their respective values inside them.) So it again makes perfect sense for the addresses for consecutive members be different.
You might want to check out this code (which I believe is more instructive):
(Note: beware that there is "undefined behavior" in my particular use of pointer arithmetic here, so this in not completely correct C++. But to my knowledge it works fine. It's here for demonstration purposes anyways, so don't use this in production!)
#include <cstddef>
#include <iostream>
#include <string>
template <typename T, typename U>
ptrdiff_t Dist (T const * from, U const * to) {
return reinterpret_cast<char const *>(to) - reinterpret_cast<char const *>(from);
}
class A{
public:
A( ) : m_x( 3 ) { };
void printOffsetsAndSizes () const {
std::cout << "A: " << reinterpret_cast<uintptr_t>(this) << " (" << sizeof(*this) << ")" << std::endl;
std::cout << " m_x: " << Dist(this, &m_x) << " (" << sizeof(m_x) << ")" << std::endl;
std::cout << " m_c: " << Dist(this, &m_c) << " (" << sizeof(m_c) << ")" << std::endl;
std::cout << " m_y: " << Dist(this, &m_y) << " (" << sizeof(m_y) << ")" << std::endl;
std::cout << " m_s: " << Dist(this, &m_s) << " (" << sizeof(m_s) << ")" << std::endl;
}
private:
int m_x;
int m_c;
char m_y;
std::string m_s;
};
int main () {
A a;
a.printOffsetsAndSizes ();
return 0;
}
which gives this output on Ideone:
A: 3213332880 (16)
m_x: 0 (4)
m_c: 4 (4)
m_y: 8 (1)
m_s: 12 (4)

Packing non-POD type: no warning, unexpected size?

Here is a rather contrived series of types. A2 is just a non-POD version of A:
template <size_t N>
struct A {
char data[N];
} __attribute__((packed));
template <size_t N>
struct A2 {
A2() { // actual body not significant
memset(data, 0, N);
}
char data[N];
} __attribute__((packed));
template <template <size_t> class T>
struct C {
T<9> a;
int32_t i;
T<11> t2;
} __attribute__((packed));
//}; // oops, forgot to pack
template <template <size_t> class T>
struct B : C<T> {
char footer;
} __attribute__((packed));
As-is, sizeof(B<A>) == sizeof(B<A2>) == 25. I get no warnings compiling with -Wall -pedantic (this is gcc 4.9.0).
But now, let's say I forgot to pack C. Now I get:
sizeof(B<A>) == 32
sizeof(B<A2>) == 28
Still no warnings. What happened here? How is B<A2> smaller than B<A>? Is this just undefined behavior due to A2 not being POD?
If I reorganize B to look have a C<T> member instead of inheriting from it, then and only then do I get a warning:
ignoring packed attribute because of unpacked non-POD field ‘C B::c’
[Update] In response to IdeaHat's comments, here are some other the offsets:
B<A> B<A2>
a 0 0
i 12 12
t2 16 16
footer 28 27
And
sizeof(C<A>) == 28
sizeof(C<A2>) == 28
[Update 2] I see the same behavior on clang with respect to the offsets, except that sizeof(B<A>) is 29 instead of 32.
That behaviour is due to the compiler is allowed to apply optimizations in a non-POD type (e.g.: C<A2>).
It doesn't apply to POD types (e.g.:C<A>).
I've found this related question with a very helpful answer by Kerrek SB:
When extending a padded struct, why can't extra fields be placed in the tail padding?
On the other hand, you can force this optimization regardless the POD'ness with the -fpack-struct option in GCC. Although not recommended, it's useful for the example.
#include <stdint.h>
#include <stdio.h>
struct C {
int16_t i;
char t[1];
};
struct C2 {
C2() {}
int16_t i;
char t[1];
};
template <class T>
struct B : T {
char footer;
};
int main(void) {
printf("%lu\n", sizeof(B<C>));
printf("%lu\n", sizeof(B<C2>));
return 0;
}
If you compile it with -fpack-struct (gcc-4.7):
sizeof(B<C>) == sizeof(B<C2>) == 4
If not:
sizeof(B<C>) == 6
sizeof(B<C2>) == 4
From man gcc (4.7):
-fpack-struct[=n]
Without a value specified, pack all structure members together
without holes.
When a value is specified (which must be a small power of two),
pack structure members according to this value, representing
the maximum alignment (that is, objects with default alignment
requirements larger than this will be output potentially
unaligned at the next fitting location.
Warning: the -fpack-struct switch causes GCC to generate code
that is not binary compatible with code generated without that
switch.
Additionally, it makes the code suboptimal. Use it to conform
to a non-default application binary interface.
As you can see, when a class is POD and it acts as the base class of another class, that base is not packed unless you force it. i.e.: it doesn't use the tail padding of the base.
In the particular case of the C++ ABI which GCC uses, there's a discussion about this:
It looks like the ABI document meant to require the reuse of tail-padding
in non PODs, but it doesn't actually say that.
Consider this case, as the canonical example:
struct S1 {
virtual void f();
int i;
char c1;
};
struct S2 : public S1 {
char c2;
};
I think the ABI meant to say that you put "c2" in the tail padding for
S1. (That is what G++ implements, FWIW.)
Take a look at what the Itanium ABI C++ (this is the one GCC uses) specifies about tail padding:
This ABI uses the definition of POD only to decide whether to allocate objects in the tail-padding of a base-class subobject. While the standards have broadened the definition of POD over time, they have also forbidden the programmer from directly reading or writing the underlying bytes of a base-class subobject with, say, memcpy. Therefore, even in the most conservative interpretation, implementations may freely allocate objects in the tail padding of any class which would not have been POD in C++98. This ABI is in compliance with that.
In addition, here's the reason why the C++ ABI doesn't use the tail padding of POD objects:
We ignore tail padding for PODs because an early version of the standard did not allow us to use it for anything else and because it sometimes permits faster copying of the type.
In your example, C<A> is POD and for that reason the ABI is not using its tail padding when the type act as the base class of B<A>.
For that, C<A> remains with padding (and occupying 28 bytes as it) and footer occupies 4 bytes respecting the alignment.
Finally, I want to share the code I used to make some test, previously to find a proper answer. You can find it useful in order to see what the compiler ABI does with the objects in C++(11) (GCC).
Test code
#include <iostream>
#include <stddef.h>
struct C {
int16_t i;
char t[1];
};
struct C2 {
C2() {}
int16_t i;
char t[1];
};
template <class T>
struct B : T {
char footer;
};
int main(void) {
std::cout << std::boolalpha;
std::cout << "standard_layout:" << std::endl;
std::cout << "C: " << std::is_standard_layout<C>::value << std::endl;
std::cout << "C2: " << std::is_standard_layout<C2>::value << std::endl;
std::cout << "B<C>: " << std::is_standard_layout<B<C>>::value << std::endl;
std::cout << "B<C2>: " << std::is_standard_layout<B<C2>>::value << std::endl;
std::cout << std::endl;
std::cout << "is_trivial:" << std::endl;
std::cout << "C: " << std::is_trivial<C>::value << std::endl;
std::cout << "C2: " << std::is_trivial<C2>::value << std::endl;
std::cout << "B<C>: " << std::is_trivial<B<C>>::value << std::endl;
std::cout << "B<C2>: " << std::is_trivial<B<C2>>::value << std::endl;
std::cout << std::endl;
std::cout << "is_pod:" << std::endl;
std::cout << "C: " << std::is_pod<C>::value << std::endl;
std::cout << "C2: " << std::is_pod<C2>::value << std::endl;
std::cout << "B<C>: " << std::is_pod<B<C>>::value << std::endl;
std::cout << "B<C2>: " << std::is_pod<B<C2>>::value << std::endl;
std::cout << std::endl;
std::cout << "offset:" << std::endl;
std::cout << "C::i offset " << offsetof(C, i) << std::endl;
std::cout << "C::t offset " << offsetof(C, t) << std::endl;
std::cout << "C2::i offset " << offsetof(C2, i) << std::endl;
std::cout << "C2::t offset " << offsetof(C2, t) << std::endl;
B<C> bc;
std::cout << "B<C>.i: " << (int)(reinterpret_cast<char*>(&bc.i) - reinterpret_cast<char*>(&bc)) << std::endl;
std::cout << "B<C>.t: " << (int)(reinterpret_cast<char*>(&bc.t) - reinterpret_cast<char*>(&bc)) << std::endl;
std::cout << "B<C>.footer: " << (int)(reinterpret_cast<char*>(&bc.footer) - reinterpret_cast<char*>(&bc)) << std::endl;
B<C2> bc2;
std::cout << "B<C2>.i: " << (int)(reinterpret_cast<char*>(&bc2.i) - reinterpret_cast<char*>(&bc2)) << std::endl;
std::cout << "B<C2>.t: " << (int)(reinterpret_cast<char*>(&bc2.t) - reinterpret_cast<char*>(&bc2)) << std::endl;
std::cout << "B<C2>.footer: " << (int)(reinterpret_cast<char*>(&bc2.footer) - reinterpret_cast<char*>(&bc2)) << std::endl;
std::cout << std::endl;
std::cout << "sizeof:" << std::endl;
std::cout << "C: " << sizeof(C) << std::endl;
std::cout << "C2: " << sizeof(C2) << std::endl;
std::cout << "DIFFERENCE:\n";
std::cout << "B<C>: " << sizeof(B<C>) << std::endl;
std::cout << "B<C2>: " << sizeof(B<C2>) << std::endl;
std::cout << "B<C>::C: " << sizeof(B<C>::C) << std::endl;
std::cout << "B<C2>::C: " << sizeof(B<C2>::C2) << std::endl;
std::cout << std::endl;
std::cout << "alignment:" << std::endl;
std::cout << "C: " << std::alignment_of<C>::value << std::endl;
std::cout << "C2: " << std::alignment_of<C2>::value << std::endl;
std::cout << "B<C>: " << std::alignment_of<B<C>>::value << std::endl;
std::cout << "B<C2>: " << std::alignment_of<B<C2>>::value << std::endl;
std::cout << "B<C>::C: " << std::alignment_of<B<C>::C>::value << std::endl;
std::cout << "B<C2>::C2: " << std::alignment_of<B<C2>::C2>::value << std::endl;
std::cout << "B<C>.i: " << std::alignment_of<decltype(std::declval<B<C>>().i)>::value << std::endl;
std::cout << "B<C>.t: " << std::alignment_of<decltype(std::declval<B<C>>().t)>::value << std::endl;
std::cout << "B<C>.footer: " << std::alignment_of<decltype(std::declval<B<C>>().footer)>::value << std::endl;
std::cout << "B<C2>.i: " << std::alignment_of<decltype(std::declval<B<C2>>().i)>::value << std::endl;
std::cout << "B<C2>.t: " << std::alignment_of<decltype(std::declval<B<C2>>().t)>::value << std::endl;
std::cout << "B<C2>.footer: " << std::alignment_of<decltype(std::declval<B<C2>>().footer)>::value << std::endl;
return 0;
}
Output with gcc-4.7
standard_layout:
C: true
C2: true
B<C>: false
B<C2>: false
is_trivial:
C: true
C2: false
B<C>: true
B<C2>: false
is_pod:
C: true
C2: false
B<C>: false
B<C2>: false
offset:
C::i offset 0
C::t offset 2
C2::i offset 0
C2::t offset 2
B<C>.i: 0
B<C>.t: 2
B<C>.footer: 4
B<C2>.i: 0
B<C2>.t: 2
B<C2>.footer: 3
sizeof:
C: 4
C2: 4
DIFFERENCE:
B<C>: 6
B<C2>: 4
B<C>::C: 4
B<C2>::C: 4
alignment:
C: 2
C2: 2
B<C>: 2
B<C2>: 2
B<C>::C: 2
B<C2>::C2: 2
B<C>.i: 2
B<C>.t: 1
B<C>.footer: 1
B<C2>.i: 2
B<C2>.t: 1
B<C2>.footer: 1