0

I have a struct Foo from an external API library, which is in C, and above which I am writing a C++ interface.

So I have a class like this:

class ClassFoo
{
public:
    ClassFoo(const Foo * ptr) : ptr(ptr) { }
    ~ClassFoo();

    bool method1();
    int method2();
    ... (other methods)
private:
    const Foo * ptr;
}

Then, the external library defines another struct Bar which is a collection of Foos, a method for getting the number of foos, and a method for retrieving an array of Foo* pointers:

int APIbarGetNumFoos(const Bar* ref);
void APIbarGetFoos(const Bar* ref, int maxSize, const Foo* foos[]);

I define a ClassBar like this:

class ClassBar
{
public:
    ClassBar(const Bar * ptr) : ptr(ptr) { }
    ~ClassBar();

    std::vector<ClassFoo> getFoos();

    ... (other methods)
private:
    const Bar * ptr;
}

Now the question : for memory & speed efficiency, I want to avoid allocating an array of Foo* to call the C API, then copy everything to the result vector.

Does C++ guarantees that ClassFoo instance only contains a Foo* pointer, and that its size is the size of a pointer, if I do not use any virtual methods (to avoid the vtables), so that I can define getFoos() like that:

std::vector<ClassFoo> ClassBar::getFoos()
{
    int size = APIbarGetNumFoos(ptr);
    std::vector<ClassFoo> result(size);
    APIbarGetFoos(ptr, size, (const Foo**) &result[0]);
    return result;
}

In other words, can I be sure that an array of ClassFoo will be in memory strictly the same as an array of Foo* ?

Thanks!

Etienne

galinette
  • 8,896
  • 2
  • 36
  • 87
  • 1
    An array of `ClassFoo` definitely won't be the same as an array of `Foo`. Do you mean the same as an array of `Foo*`? – BoBTFish May 30 '13 at 10:59
  • 2
    Perhaps not guaranteed, but it should work on most implementations. Besides, you need to cast to `Foo**`, not `Foo*`. – riv May 30 '13 at 11:04
  • Yup, I missed two `*` as I actually has a FooRef struct that trivially contains the Foo*, but I simplified the example... Fixed now – galinette May 30 '13 at 13:42

3 Answers3

3

You can use static_assert:

static_assert(sizeof(Foo*) == sizeof(ClassFoo), "Sizes don't match!");

Then you'll have a compile-time error if the sizes don't match. Purists may say this is still not strict enough, but in practice it's probably OK.

By the way, here:

(const Foo*) &result[0]

I think you might mean:

reinterpret_cast<const Foo**>(&result[0]);
leemes
  • 44,967
  • 21
  • 135
  • 183
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • `reinterpret_cast` will not guarantee that the pointer address is the same, which will lead to a crash in such cases. `static_cast` is the correct way, I guess – galinette May 30 '13 at 13:54
1

I believe the short answer is: Yes!

C++ objects (that don't contain vtables) are just like C structs, and methods are just like C functions with an inplicit this parameter.

I'm not sure whether that's true if you have RTTI enabled though.

ams
  • 24,923
  • 4
  • 54
  • 75
  • 1
    Only if he doesn't define ctors, etc. [PODs](http://stackoverflow.com/questions/146452/what-are-pod-types-in-c). – BoBTFish May 30 '13 at 11:01
  • 1
    ctors don't affect class size; virtual functions do. – riv May 30 '13 at 11:05
  • Constructors prevent a class being described as POD because it makes them hard to use in unions, but they don't have any actual presence in the object, I think. – ams May 30 '13 at 11:09
  • 2
    If the class is not a POD it might still be trivially copyable. See http://en.cppreference.com/w/cpp/types/is_trivially_copyable – rwols May 30 '13 at 11:11
  • 1
    Also, the concept relevant *here* is standard_layout (http://en.cppreference.com/w/cpp/types/is_standard_layout), which is also independent of non-virtual methods, ctors, dtors, etc. –  May 30 '13 at 11:30
  • I don't believe the layout is significant. The question is whether an array of pointers to C struct is more efficient than an array of objects that contain the same pointer. – ams May 30 '13 at 12:21
  • @ams : actually, std::is_pod returns true even with a constructor, so this seems not true – galinette May 30 '13 at 13:35
  • @galinette: I believe it's possible to write a constructor for which that is not true. – ams May 30 '13 at 16:11
0

From the responses and comments, it appears that:

  • It works on a recent gcc (4.8) and seems to work on main compilers
  • One can guarantee this at compilation by using: (tested on gcc 4.8)

    static_assert(! std::is_pod<ClassFoo>::value, "Foo* cannot be copied to ClassFoo");

  • It may bee less restrictive and still OK to use is_standard_layout instead of is_pod

galinette
  • 8,896
  • 2
  • 36
  • 87