I have a C library that has types like this:
typedef struct {
// ...
} mytype;
mytype *mytype_new() {
mytype *t = malloc(sizeof(*t));
// [Initialize t]
return t;
}
void mytype_dosomething(mytype *t, int arg);
I want to provide C++ wrappers to provide a better syntax. However, I want to avoid the complication of having a separately-allocated wrapper object. I have a relatively complicated graph of objects whose memory-management is already more complicated than I would like (objects are refcounted in such a way that all reachable objects are kept alive). Also the C library will be calling back into C++ with pointers to this object and the cost of a new wrapper object to be constructed for each C->C++ callback (since C doesn’t know about the wrappers) is unacceptable to me.
My general scheme is to do:
class MyType : public mytype {
public:
static MyType* New() { return (MyType*)mytype_new(); }
void DoSomething(int arg) { mytype_dosomething(this, arg); }
};
This will give C++ programmers nicer syntax:
// C Usage:
mytype *t = mytype_new();
mytype_dosomething(t, arg);
// C++ Usage:
MyType *t = MyType::New();
t->DoSomething(arg);
The fib is that I’m downcasting a mytype* (which was allocated with malloc()) to a MyType*, which is a lie. But if MyType has no members and no virtual functions, it seems like I should be able to depend on sizeof(mytype) == sizeof(MyType), and besides MyType has no actual data to which the compiler could generate any kind of reference.
So even though this probably violates the C++ standard, I’m tempted to think that I can get away with this, even across a wide array of compilers and platforms.
My questions are:
- Is it possible that, by some streak of luck, this does not actually violate the C++ standard?
- Can anyone think of any kind of real-world, practical problem I could run into by using a scheme like this?
EDIT: @James McNellis asks a good question of why I can’t define MyType as:
class MyType {
public:
MyType() { mytype_init(this); }
private:
mytype t;
};
The reason is that I have C callbacks that will call back into C++ with a mytype*, and I want to be able convert this directly into a MyType* without having to copy.
I’m not advocating this style, but as
MyTypeandmytypeare both PODs, I believe the cast does not violate the Standard. I believeMyTypeandmytypeare layout-compatible (2003 version, Section 9.2, clause 14: “Two POD-struct … types are layout-compatible if they have the same number of nonstatic data members, and corresponding nonstatic data members (in order) have layout-compatible types (3.9).”), and as such can be cast around without trouble.EDIT: I had to test things, and it turns out I’m wrong. This is not Standard, as the base class makes
MyTypenon-POD. The following doesn’t compile:Visual C++ gives the error message that “Types with a base are not aggregate.” Since “Types with a base are not aggregate,” then the passage I quoted simply doesn’t apply.
I believe that you’re still safe in that most compilers will make
MyTypelayout-compatible with withmytype. The cast will “work,” but it’s not Standard.