Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I rely on contiguous memory in this case?

Tags:

c++

Consider a class:

template <typename T>
struct A{
  //...many public member functions...
  T x;
  T y;
  T z;
}

And another, similar:

template <typename T>
struct B{
  //many public member functions
  T x;
  T y;
}

While not specified here, T will always be either float or int or bool.

Now consider another struct:

struct Pair{
  A<float> a;
  B<float> b;
 }

Now a vector:

 std::vector<Pair> bigBunch;

How safe is it to assume that all the x, y, z in bigBunch will be contiguous? I know that vector guarantees contiguous memory between its Pairs but I also know that struct does not necessarily guarantee contiguous memory since padding can happen. However, I thought padding is only a risk if your struct elements are different types.

I'd like to be able to get a pointer to bigBunch[0].a.x and then know that I can expect a contiguous stream of floats throughout the entire contents of bigBunch. And actually, a pointer to bigBunch[0].a.x would point to the same place as just saying `bigBunch[0].a.

Would it matter if Pair.a and Pair.b were the same or different type, such as mixing ints and float rather than both being the same type (float in this example)?

like image 435
johnbakers Avatar asked Jan 24 '26 00:01

johnbakers


1 Answers

AFAIK, nothing in the standard precludes the compiler from adding padding if it thinks it's a good idea. The compiler really has a lot of leeway in this matter. Which means the best thing to do is to be defensive and explicitly instruct your compiler to pack the data, even if eg, 4 byte float on 4 byte boundaries shouldn't cause padding.

My other recommendation is to use static_assert to verify everything is the size you want. Eg,

template <typename T>
struct A{
  //...many public member functions...
  T x;
  T y;
  T z;
} __attribute__ ((__packed__));
static_assert(sizeof(A) == 3*sizeof(T), "struct A shouldn't be padded");

If you don't have C++ 11, you can use BOOST_STATIC_ASSERT instead. EDIT: the __attribute__ ((__packed__)) bit after struct's closing brace is GCC-specific way of ensuring tightly packed struct.

Another thing you should consider is if you really get a benefit out of being able to treat your vector<Pair> as a big float array with no gaps. I understand that may make some algorithms more convenient to write if you have to iterate over everything, or if you have to pass the data to some other library that expects contiguous data. But I'm guessing you are doing a lot of math with these structs, and your compiler may be able to auto-vectorize some of it, eg by using SSE if struct A was 128-bit aligned. There is a lot of guesswork on my part in this part of my answer, so ignore it if it doesn't apply to you.

PS: don't forget the semicolon after the closing brace of your structs.

like image 180
Nicu Stiurca Avatar answered Jan 26 '26 15:01

Nicu Stiurca



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!