nriedlin
nriedlin

Reputation: 195

Size of a struct containing 1 Pointer

Suppose I have the following class template:

template<typename T>
struct Wrapper {
  T* t_;
  static void check() {
    static_assert(sizeof(Wrapper<T> == sizeof(T*), "Illegal assumption");
  }
};

I looked in the C99 standard an in the C++03 standard and cannot find a guarantee for my assumption expressed in the static_assert. I tried it on Visual C++ 2008 and 2010 (32bit) and gcc on linux (64bit) using several compiler options and found my assumption confirmed.

My question are:

I guess a compiler might add some padding to the struct e.g. for debugging purposes. But is there a compiler that actually does that?

Edit: So as you asked here is what I want to achieve:
I have the member function with the following signature:

Someclass* OtherClass::fn();

I want to change the signature like this:

Wrapper<Someclass> OtherClass::fn();

This wrapper acts like some smart-pointer, i.e. it cares for the pointer's lifetime, thus it releases it when it goes out of scope. As the function is called across a dll boundary I want to make sure that the returned value (which is now a concrete type, not just a dumb pointer) is in all circumstances (i.e. compiler settings, etc) of the same size as the pointer would be. The plan/hope is to support all combination of debug/release application/dll builds.
As you might ask: no, I can not use boost::shared_ptr<>, std::shared_ptr<>, std::unique_ptr<> and the like, as we don't want to expose boost to the dll user and we don't support C++11 yet.

Upvotes: 5

Views: 211

Answers (3)

Jerry Coffin
Jerry Coffin

Reputation: 490663

I'd say your assumption is reasonable with most compilers and flags.

For any T, the compiler is able to create arrays of T, which are required to be contiguous, so it has to be able to create that without padding. As such, any padding it put into your struct would be purely optional, not something that could be required.

On the other hand, I'm reasonably certain none of the C or C++ standards guarantees what you're asking. The closest to guarantees about it would stem from the fact that in C++ it's a standard layout struct, which restricts the C++ compiler to laying out the fields about like a C compiler would, so the members must be ascending order with no padding at the beginning -- but padding between members and/or after the last member are still allowed.

Bottom line: if you have a pointer to the first member, you can convert to pointer to struct (or vice versa) safely. You're on your own if you do something like creating an array of one and indexing into it as if it were an array of the other -- chances of it working are quite good, but I'm pretty sure the standard doesn't guarantee it.

Upvotes: 1

Matthieu M.
Matthieu M.

Reputation: 300349

Looking into the standard I found two interesting bits in § 9.2 [class.mem]:

17/ Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9).

So, two struct with only a pointer in them would be layout compatible (thus if your assertion holds for this type, it holds for all types).

20/ A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. —end note ]

In the note we learn that there cannot be padding at the beginning of a structure.


Depending on your goal, 20/ might be sufficient. It means that this works:

void check(T* t) {
    Wrapper<T>* w = reinterpret_cast<Wrapper<T>*>(t);
    assert(w->t_ == t);
}

Upvotes: 1

Lou Franco
Lou Franco

Reputation: 89232

If you want to assume it and you have a compile-time check, then go ahead. Presumably you get some benefit out of doing this.

You aren't guaranteed anything about padding, but typically padding is used to get alignment so that arrays of the type have every member of the array (and every member of the struct) aligned properly. A native pointer is usually already the right size to be aligned, so padding isn't needed, but you aren't guaranteed that.

This isn't something you can just check with gcc -- it depends on the target architecture, not only the compiler.

Upvotes: 3

Related Questions