Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost compressed_pair and addresses of empty objects

AFAIK, boost::compressed_pair is supposed to ensure that the address of the first and second memebrs are different while it does its magic of compressing the pair. It says so here. Seems like it is not the case and its behavior is different on different compilers. I'm using boost v 1.47. What am I missing?

struct E1 {};
struct E2 {};

boost::compressed_pair<E1, E2> diff_pair;
boost::compressed_pair<E1, E1> same_pair;

// clang++ and g++ 4.7 print the same address but VC2010 prints different addresses.
printf("different pairs = %p, %p\n", &diff_pair.first(), &diff_pair.second());

// clang++ and g++ 4.7 print different addresses but VC2010 prints the same address.
printf("different pairs = %p, %p\n", &same_pair.first(), &same_pair.second());
like image 683
Sumant Avatar asked Oct 08 '11 01:10

Sumant


1 Answers

When the types are different and one or both of the types is an empty class, the subobjects are supposed to be at the same address (if the compiler can pull the empty base class optimization off), that's the point of the compressed pair.

When the types are the same, I think a note from chapter 10 in the standard applies:

A base class subobject may be of zero size (Clause 9); however, two subobjects that have the same class type and that belong to the same most derived object must not be allocated at the same address (5.10).

So it seems it is up to the compiler to ensure that they are allocated at different addresses (and VC10 might be getting it wrong).

The comments in the boost's header indicate, that earlier they didn't bother to put two different instances of the same empty class in the compressed pair at all. Instead they just stored one instance and both first() and second() returned the same object.

   // 4    T1 == T2, T1 and T2 both empty
   //      Originally this did not store an instance of T2 at all
   //      but that led to problems beause it meant &x.first() == &x.second()
   //      which is not true for any other kind of pair, so now we store an instance
   //      of T2 just in case the user is relying on first() and second() returning
   //      different objects (albeit both empty).
like image 113
UncleBens Avatar answered Nov 05 '22 18:11

UncleBens