Are Class Members Guaranteed to Be Contiguous in Memory

Are members in a c++ class guaranteed be contiguous?

Because your class is not a polymorphic type, has no base class, and all the members are public, the address of x is guaranteed to be the address of the class.

Also, the address of y is guaranteed to be after the address of x, although there could be an arbitrary amount of padding between them. So yes, your result is a coincidence.

If your class is polymorphic, i.e. has a virtual function somewhere in either it or a base class, or the members are protected or private, then all bets are off.

So in your case, (void*)&(this->x) is (void*)this, and the address of this->y must be higher than the address of this->x.

Finally if you need the class members to be contiguous, and mutually reachable by pointer arithmetic, use

int x[2];

instead as the member.

Are class members guaranteed to be contiguous in memory?

It is guaranteed that they appear with increasing addresses in the order declared. This is true in general of data members without intervening access specifiers, so if there are other data members in the class then the only way they could intervene is if there are access specifiers in there.

I don't think it's guaranteed to be safe to modify padding bytes. I don't think it's guaranteed that the implementation won't put "something important" in between data members, although I can't immediately think of anything an implementation would want to put in there. Type information for a strangely-designed accurate-marking GC? Recognizable values to test for buffer overruns?

It's not guaranteed that all-bits-zero represents a null function pointer.

You could deal with the issue of the all-bits-zero representation using something like:

std::fill(&func1, &func4 + 1, (void(*)(void))0);

but that would still leave the issue of padding. You're guaranteed no padding in an array, but not (by the standard) in a class. The ABI used by your implementation might specify struct layout to the degree necessary to ensure that your class above is laid out the same as an array of 4 function pointers.

An alternative is to do the following:

struct function_pointers {
void (*func1)();
void (*func2)();
void (*func3)();
void (*func4)();
};

class C : private function_pointers
{
public:
C() : function_pointers() {}
};

The initializer function_pointers() dictates that (since it doesn't have a user-declared constructor) the members of function_pointers are zero-initialized even if the instance of C itself is only default-initialized. function_pointers could be a data member rather than a base class, if you prefer to type a bit more to access func1 etc.

Note that C is now non-POD in C++03. In C++11 C remains standard-layout after this change, but would not be standard-layout if there were any data members defined in C, and it is not a trivial class. So if you were relying on POD/standard/trivial-ness then don't do this. Instead leave the definition of C as it is and use aggregate initialization (C c = {0};) to zero-initialize instances of C.

C++ Contiguous memory access for object data members

  • The standard guarantees that they will be in that order in memory

    (if you took their addresses they would increment).

  • It does not guarantee that they will be in contiguous memory; but if that is the most optimal layout then they probably will be. Compiler is allowed to add padding between members (it usually does this to make access more efficient (sacrifice space for speed)). If all the members are the same size this is unlikely.

Note: Introducing public/private/protected between them complicates things and may change the order.

Are you better of using an array?

That depends. Would you normally accesses them via an index or via the name? I would say thay 99% of the time the first version you have is better but I can imagine use cases where std::array<> could be useful (members accessed via an index).

It was suggested in the comments std::vector<> could also be used. This is true and the standard guarantees the members are in contiguous location, but they may not be local to the object (in a std::array<> they are local to the object).

In Java, are all members of a class stored in contiguous memory?

But when studying Go in detail, I often read about this being a bad
idea unless you really need them to be pointers, because it means the
values for each member can be spread anywhere across dynamic memory,
hurting performance because it's less able to take advantage of
spatial locality in the CPU.

You have no choice in Java.

class MyClass {
String firstMember;
int secondMember;
}

The String-valued member is, and can only be, a reference (i.e., effectively a pointer). The int-valued member is a primitive value (i.e., not a pointer).

The Java world is divided into primitive values and objects (of some class, or arrays, and so on). Variables for the former types are not references, variables for the latter types are references.

The Java Language Specification does not talk about object layout at all; that's not a concept that appears in the language.

The JVM Specification specifically says

The Java Virtual Machine does not mandate any particular internal
structure for objects.

Pragmatically, you might guess that the body of a class instance is a single piece of memory, but that still leaves open the questions of alignment, padding, and ordering or members (no reason to keep source-code order that I can see, and some reasons to reorder).

Is order in memory guaranteed for class private members in C++?

They are guaranteed to have increasing addresses with respect to each other ([class.mem]/13):

Nonstatic data members of a (non-union) class with the same access
control
(Clause [class.access]) are allocated so that later members
have higher addresses within a class object.

Note the text I marked in bold. While it's guaranteed field2 is after field1 when they are both private, it need not be the case if they had different access control. And of course, intermediate padding is always an option.

But if you want to force the absence of padding, and they are of the same type, an array would do it:

uint64_t field[2];

It also makes &field[0] + 1 well defined, since those objects are now obviously members of the same array.

Is the memory allocated for struct members continguous? What if a struct member is an array?

They will not necessarily be contiguous in memory. This is due to struct padding.

However, in your particular case, it may very well be contiguous. But if you changed the order to something like this:

struct test
{
char gender;
int age;
double height;
}

then they most likely will not be. However, in your particular case, you will still likely get padding after gender, to realign the struct to 8 bytes.


The difference between SoA (Struct of Arrays) and AoS (Array of Structs) would be like this:

SoA:

-----------------------------------------------------------------------------------
| double | double | double | *pad* | int | int | int | *pad* | char | char | char |
-----------------------------------------------------------------------------------

AoS:

-----------------------------------------------------------------------------------
| double | int | char | *pad* | double | int | char | *pad* | double | int | char |
-----------------------------------------------------------------------------------

Note that AoS pads within each struct. While SoA pads between the arrays.

These have the following trade-offs:

  1. AoS tends to be more readable to the programmer as each "object" is kept together.
  2. AoS may have better cache locality if all the members of the struct are accessed together.
  3. SoA could potentially be more efficient since grouping same datatypes together sometimes exposes vectorization.
  4. In many cases SoA uses less memory because padding is only between arrays rather than between every struct.

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

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.

Structure with an array, is memory contiguous?

Yes, a, (the elements of) b, and c will be contiguous, if we ignore possible padding between a and b, or b and c. Of course there's no padding between the elements of b.

Are the same type variables in struct guaranteed to be in contiguous in memory wothout any padding?

It is not guaranteed that the structure members are continuous in memory. you can enclose the structure definition by #pragma() statements.

#pragma pack(1)
typedef struct m_struct {
uint32_t a;
uint8_t b;
int32_t c;
} M_STRUCT;
#pragma pack() // restore the default packing

In the example above, the structure members packed without padding.

This works only if the processor allows unaligned access.

However, if you use pointers, than the size taken by the pointer depend on the machine's bit size.

Note: Tested with GCC.

Are the instance variables for an object stored in continguous memory

In general, the answer is yes; but this is un-specified. There is a library specifically designed for this, that you can play around with.

For example for a class like:

static class Example {
byte b = 1;
int x = 3;
long l= 12;
}

You can see its layout (via ClassLayout.parseClass(Example.class).toPrintable()):

 Example object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 12 (object header) N/A
12 4 int Example.x N/A
16 8 long Example.l N/A
24 1 byte Example.b N/A
25 7 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 7 bytes external = 7 bytes total

Notice how fields have changed their position (to make the padding less), plus the fact that there is a 7 bytes padding.

Things get more and more interesting the deeper you look into this, like inheritance for example, or for Objects that are made of other Objects. The examples in that library are very rich in this manner.



Related Topics



Leave a reply



Submit