Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::tuple memory alignment

Is there any formal specification for the layout and memory alignment for the pseudo members of a tuple?

Is there anyway to modify the memory alignment of types in a tuple? Is it effected by a #pragma pack() directive?

For example:

typedef std::tuple<uint8_t, uint32_t> myTuple;

Is there any specification that says this will be in memory the same as:

#pragma pack() // Default packing
struct myStruct
{
    uint8_t first;
    uint32_t second;
}

Apologies if this is a stupid question but I don't entirely understand alignment when it comes to templates.

Edit: Example of what I'm trying to accomplish

Currently I have something along the lines of...

#pragma pack(push)
#pragma pack(4)
struct cTriangle
{
    uint32 Index[3];
};
#pragma pack(pop)

template <class T>
inline bool Read(cFileStream& fStream, std::vector<T>& vec)
{
    if (!vec.size())
        return true;

    // fStream.Read(void* pBuffer, size_t Size)
    // Just a wrapper around a binary ifstream really
    return fStream.Read(&vec[0], sizeof(T) * vec.size());
}

std::vector<cVector3> vPoint;
vPoint.resize(Verticies);
bool result = Read(FileStream, vPoint);

If I wanted to typedef cTriangle as std::tuple<uint32, uint32, uint32> for metaprogramming purposes would I still be able to read/write to the raw memory of the tuple (and thus a vector of tuples) or would that memory have unknown alignment?

like image 248
NtscCobalt Avatar asked Jan 30 '13 05:01

NtscCobalt


3 Answers

Not only is there no requirement that the objects be arranged any particular way, but many tuple implementations actually put the second object before the first one.

like image 63
David Schwartz Avatar answered Nov 04 '22 09:11

David Schwartz


Tuples are typically not standard-layout, because standard-layout classes can have at most one class in their inheritance hierarchy with non-static data members, and the typical way to implement variadic tuple is through recursive inheritance, with each level of recursion adding one data member. This allows tuple implementations to elide distinct empty members through the empty base class optimisation, which is not available for struct members.

If you check that sizeof(myTuple) == sizeof(myStruct), you are reasonably entitled to assume that the memory layout of the tuple contains the elements of the struct in some (consistent) order, but actually relying on that for aliasing will likely cause undefined behaviour.

If as you say you just want alias with tuple for metaprogramming, you'd be better off using a metaprogramming library such as Boost.Fusion that allows you to annotate the struct type with its members:

#pragma pack(push)
#pragma pack(4)
struct cTriangle {
    uint32 Index[3];
};
#pragma pack(pop)
BOOST_FUSION_ADAPT_STRUCT(
    cTriangle,
    (uint32[3], Index))
like image 32
ecatmur Avatar answered Nov 04 '22 07:11

ecatmur


As David points out, there is no guarantee according to the standard. However, if you are interested in a two value tuple, you might want to use std::pair<T1, T2>, which is standard-layout (if T1,T2 are standard-layout) and thus has predictable memory layout.

See also C++0x Tuples Store Elements Backwards

[EDIT]

Sorry, I had not seen ecatmur's answer before answering your comment. By the way: If all members of your struct have the same type, you can of course use std::array, which is standard layout and which allows element access with std::get similar to std::tuple.

like image 1
Claas Avatar answered Nov 04 '22 08:11

Claas