1

I just discovered that with my STL-implementaton (VS2019) the address-order of the parts of a tuple is reverse. Look at this code:

#include <iostream>
#include <tuple>

using namespace std;

int main()
{
    tuple<string, string> tss( "try", "this" );
    cout << &get<1>( tss ) - &get<0>( tss ) << endl;
}

The output is:

-1

Is there a guaranted order of addresses inside a tuple or is it implementation-defined ?

Bonita Montero
  • 2,817
  • 9
  • 22
  • It is unspecified. That means no guaranteed order, and is distinct from implementation-defined (which means that it would also need to be described in documentation for the implementation). – Peter Oct 24 '21 at 06:58
  • 1
    The other question is why it's relevant in which order the tuple members are stored. This smells like you want to use this info for something which might be U.B. – Scheff's Cat Oct 24 '21 at 09:03

1 Answers1

1

Is there a guaranted order of addresses inside a tuple?

No.

or is it implementation-defined ?

It isn't implementation defined i.e. the standard library implementation isn't required to document it. But it is unspecified by the standard and the implementation is free to use any memory order they prefer.

why is it reverse?

A typical way to implement tuple is to use recursive inheritance. It looks basically something like this:

template<class Head, class... Tail>
class tuple : tuple<Tail...>
{
    Head m;
}

A reason to use such implementation is to make use of the empty base class optimisation i.e. it allows following to be true:

struct empty{};
assert(sizeof(std::tuple<empty, int>) == sizeof(std::tuple<int>));

A consequence of this is that the memory order of members is reversed.


&get<1>( tss ) - &get<0>( tss )

The behaviour of pointer arithmetic between pointers to objects that aren't elements of an array is undefined.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • 1
    "struct empty {}; cout << sizeof(tuple) << " " << sizeof(tuple);" reports "4 8" with clang++ / clang-cl 13.0.0 on Windows and and MSVC 19.29.30136. On Linux g++ 11.1.0 reports "4 4" and clang++ 12.0.0 report "4 4". So the empty base class optimization doesn't seem to be reliable. – Bonita Montero Oct 24 '21 at 08:03
  • @BonitaMontero Optimisations are often inconsistent between implementations. – eerorika Oct 24 '21 at 09:46
  • @eeroika: It is specified that empty base classes are optimized away ... – Bonita Montero Oct 24 '21 at 10:50
  • @BonitaMontero It isn't generally specified, no. It is indirectly necessary in the case of standard layout classes though. – eerorika Oct 24 '21 at 11:24
  • @eeroika: Are standard layout classes still standard layout classes once they've been inherited and part of another class ? – Bonita Montero Oct 24 '21 at 15:24
  • @BonitaMontero a standard layout class remains standard layout class when it's a base. A class with a base can be standard layout too, but only if the base is empty. – eerorika Oct 24 '21 at 15:36