Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POD struct (members of same type): are members in contiguous memory locations?

Given

template <typename T>
struct Vector3d { T x, y, z; };
  • Is it safe to assume that x, y, and z are in contiguous memory locations?

  • Is it at least safe to assume that for T = float and T = double?

  • If not is it possible to enforce in a cross-platform way?

Note: I don't mind padding after z as long as x, y, z are contigious

like image 536
AMA Avatar asked Sep 05 '19 15:09

AMA


3 Answers

Is it safe to assume that x, y, and z are in contiguous memory locations?

There is technically no such guarantee by the language.

On the other hand, there is no need for them to not be contiguous either, and they are quite likely to be contiguous in practice.

If not is it possible to enforce in a cross-platform way?

The cross-platform way of having objects that are guaranteed to be in contiguous memory locations is an array:

template <typename T>
struct Vector3d { T components[3]; };

Arrays also make it legal to use pointer arithmetic to iterate over the objects.

like image 153
eerorika Avatar answered Oct 16 '22 16:10

eerorika


Is it safe to assume that x, y, and z are in contiguous memory locations?

The standard doesn't make such a guarantee.

But in practice, a sane implementation isn't going to insert any padding between adjacent fields of the same type (since such padding is never necessary1).

If you want extra safety, add a static_assert:

static_assert(sizeof(Vector3d<float>) == 3 * sizeof(float));

Is it at least safe to assume that for T = float and T = double?

From what I know, field type doesn't make any difference here.


1 — Arrays are guaranteed to contain no padding. Since you can make an array of any type, implementation has to be able to store objects of any single type next to each other with no padding.

like image 36
HolyBlackCat Avatar answered Oct 16 '22 16:10

HolyBlackCat


No there are absolutely no guarantees there is no padding between structure elements of the same types, even for "large" plain old data types such as a double. Furthermore the behaviour on attempting to reach an element by pointer arithmetic on a pointer to another element is undefined.

Far better to write

template <typename T>
struct Vector3d { T t[3]; };

where contiguity and pointer arithmetic are guaranteed, and provide access functions for x, y, and z.

If you don't like the syntax for calling functions, and are willing to tolerate some overhead that's most likely manifested in the struct itself, then you could always bind references:

template <typename T>
struct Vector3d
{
    T t[3];
    T& x = t[0];
    T& y = t[1];
    T& z = t[2];
};
like image 3
Bathsheba Avatar answered Oct 16 '22 16:10

Bathsheba