Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I noticed one unpleasant thing that happens with std::pair when tried to save it into binary file: std::pair is aligned to a word. It might be useful in terms of processor efficiency, but requires more storage space, so I want to switch align mode to 1-byte for std::pair. My compiler is MS VC++ 2012.

#include <iostream>
int main( )
    struct S_a { double a; size_t b; };
#pragma pack(1)
    struct S_wa { double a; size_t b; };
    std::cout << sizeof( size_t ) << '\n';                          // 4
    std::cout << sizeof( double ) << '\n';                          // 8
    std::cout << sizeof( std::pair< size_t, size_t > ) << '\n';     // 8
    std::cout << sizeof( std::pair< double, size_t > ) << '\n';     // 16 - bad
    std::cout << sizeof( S_wa ) << '\n';                            // 12 - good
    std::cout << sizeof( S_a ) << '\n';                             // 16
    std::cout << sizeof( std::pair< double, double > ) << '\n';     // 16

I tried this, but it doesn't work:

#pragma pack(1)
    typedef std::pair< double, size_t > Q;
    std::cout << sizeof( Q ) << '\n';                               // 16
                Under project properties, try changing the C/C++ -> Code Generation -> Struct Member Alignment option (/Zp1)
– Praetorian
                Aug 16, 2013 at 4:17
                Instead of screwing over your runtime, wouldn't it be better just to write special functions that handle reading and writing pair objects compactly?
– Benjamin Lindley
                Aug 16, 2013 at 4:22

The alignment of the two members is defined by the alignment in force when the template itself is defined, not just when it's used to instantiate an instance.

The Microsoft implementation of the STL uses the symbol _CRT_PACKING to define the packing used for all STL components. By default the packing is set to 8. If you define this symbol yourself before including the header that defines std::pair (<utility>) you can theoretically override the packing and set your own.

Be aware of potential problems you may encounter calling libraries or other code that assumes the standard packing.

Sorry, the pack pragma won't work for you in this situation. You could

#define _CRT_PACKING 1
#include <utility>

This can cause ALL SORTS of problems. One of which is that certain APIs, especially low-level ones, expect data to be aligned in a certain way. Not all of them are smart enough to deal with the situation where it's not; which could lead to unceremonious crashing.

If you really want the object to be serialised like this, handle the serialisation of std::pair<U,V> yourself (example only):

template<typename U, typename V>
void paircpy(char *dest, const std::pair<U, V> &pair) {
    memcpy(buffer, &pair.first, sizeof(U));
    memcpy(buffer + sizeof(U), &pair.second, sizeof(V));

You would want to handle the special case for data types that don't memcpy well.

What you really should do, for any serious project, is serialise objects in a portable way so that they're retrievable and elegantly handle things like floating point, different encodings for signed data types, pointers, arrays, STL containers and anything else where a simple dump of the object's memory is not possible or is insufficient.

Read the C++ FAQ and develop your own serialisation modules which are more than just dumping the in-memory representation of the object to file.

Alternatively, you can use a pre-packaged portable solution for serialising data types such as

  • Boost.Serialization
  • Google's Protocol Buffers
  • The XDR library
  • JSON or XML
  • Okay. I have a class ArrayFile<T> that handles a std::vector, attached to file on disk and already do some marshalling. I think, it would be right to specialize explicitly ArrayFile to T=std::pair<U,V> and reduce the alighnment there, without changing a memory allocation. ok? – Alexander Mihailov Aug 16, 2013 at 4:36 #pragma pack before #include <utility> won't do anything, because <utility> defines its own packing using the _CRT_PACKING macro. – Jonathan Potter Aug 16, 2013 at 4:38

    Alright, totally different 'solution' that may or may not be a good idea, but hey if it works who am I to stop you from knowing. It comes with all of the same caveats as the other answers, but allows you to pick and choose your poisons.

    Do a partial specialization of std::pair for the types that you care about, using the pragma pack for that particular definition, ex. for char and int:

    namespace std {
    #pragma pack( /* ... whatever you want ... */ )
    template<> struct pair<char,int> {
      char first;
      int second;
    

    With the definition somewhere you can touch it, you can affect the packing. Again, this is only good if you're willing to do it for all relevant types, and keep in mind the caveats mentioned by the other posters.

    and there's the small chance that the library you're using is crazy and decided to put more stuff in pair that the rest of the lib depends on, but you probably don't need to worry about it

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.