相关文章推荐
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

compressed_pair uses some template trickery to save space. In C++, an object (small o) can not have the same address as a different object.

So even if you have

struct A { };

A's size will not be 0, because then:

A a1;
A a2;
&a1 == &a2;

would hold, which is not allowed.

But many compilers will do what is called the "empty base class optimization":

struct A { };
struct B { int x; };
struct C : public A { int x; };

Here, it is fine for B and C to have the same size, even if sizeof(A) can't be zero.

So boost::compressed_pair takes advantage of this optimization and will, where possible, inherit from one or the other of the types in the pair if it is empty.

So a std::pair might look like (I've elided a good deal, ctors etc.):

template<typename FirstType, typename SecondType>
struct pair {
   FirstType first;
   SecondType second;

That means if either FirstType or SecondType is A, your pair<A, int> has to be bigger than sizeof(int).

But if you use compressed_pair, its generated code will look akin to:

 struct compressed_pair<A,int> : private A {
    int second_;
    A first() { return *this; }
    int second() { return second_; }

And compressed_pair<A,int> will only be as big as sizeof(int).

Was just reading this thinking, darn this guy's answer is thought out and complete, and then realised who it was, and wasn't even slightly surprised! Hey Logan! – Dominic Rodger Feb 21, 2009 at 19:30 have i missed something important? please tell me, who is this guy? i want to give him praise too :) – Johannes Schaub - litb Feb 21, 2009 at 19:43 Also, I'd like to add that compressed_pair is totally useless unless you're doing some heavy generic programming, as there are no (and I mean it) real-life situations where you put a class without data in a pair. – Viktor Sehr Sep 17, 2010 at 15:24 @ViktorSehr It seems that it could be useful for storing a custom deleter / cloner for a smart pointer class. In general, you will not have any data members in the class, but you still need to support stateful allocators / deallocators. That is what I am looking to here. I don't think this is "heavy" generic programming. – David Stone Mar 17, 2013 at 15:40

std::pair is a data type for grouping two values together as a single object. std::map uses it for key, value pairs.

While you're learning pair, you might check out tuple. It's like pair but for grouping an arbitrary number of values. tuple is part of TR1 and many compilers already include it with their Standard Library implementations.

Also, checkout Chapter 1, "Tuples," of the book The C++ Standard Library Extensions: A Tutorial and Reference by Pete Becker, ISBN-13: 9780321412997, for a thorough explanation.

Also, the boost libraries have a good implementation of tuples, if your compiler doesn't yet support TR1. – J T Mar 10, 2011 at 16:40

You sometimes need to return 2 values from a function, and it's often overkill to go and create a class just for that.

std:pair comes in handy in those cases.

I think boost:compressed_pair is able to optimize away the members of size 0. Which is mostly useful for heavy template machinery in libraries.

If you do control the types directly, it's irrelevant.

And you can use boost::tie to write code that approximates "a,b = func();". Instead of explicitly instantiating a pair, you write: "boost::tie(a,b) = func();". – rlerallut Sep 23, 2008 at 11:50

It can sound strange to hear that compressed_pair cares about a couple of bytes. But it can actually be important when one considers where compressed_pair can be used. For example let's consider this code:

boost::function<void(int)> f(boost::bind(&f, _1));

It can suddenly have a big impact to use compressed_pair in cases like above. What could happen if boost::bind stores the function pointer and the place-holder _1 as members in itself or in a std::pair in itself? Well, it could bloat up to sizeof(&f) + sizeof(_1). Assuming a function pointer has 8 bytes (not uncommon especially for member functions) and the placeholder has one byte (see Logan's answer for why), then we could have needed 9 bytes for the bind object. Because of aligning, this could bloat up to 12 bytes on a usual 32bit system.

boost::function encourages its implementations to apply a small object optimization. That means that for small functors, a small buffer directly embedded in the boost::function object is used to store the functor. For larger functors, the heap would have to be used by using operator new to get memory. Around boost version 1.34, it was decided to adopt this optimization, because it was figured one could gain some very great performance benefits.

Now, a reasonable (yet, maybe still quite small) limit for such a small buffer would be 8 bytes. That is, our quite simple bind object would not fit into the small buffer, and would require operator new to be stored. If the bind object above would use a compressed_pair, it can actually reduce its size to 8 bytes (or 4 bytes for non-member function pointer often), because the placeholder is nothing more than an empty object.

So, what may look like just wasting a lot of thought for just only a few bytes actually can have a significant impact on performance.

It's standard class for storing a pair of values. It's returned/used by some standard functions, like std::map::insert.

boost::compressed_pair claims to be more efficient: see here

std::pair comes in handy for a couple of the other container classes in the STL.

For example:

std::map<>
std::multimap<> 

Both store std::pairs of keys and values.

When using the map and multimap, you often access the elements using a pointer to a pair.

Additional info: boost::compressed_pair is useful when one of the pair's types is an empty struct. This is often used in template metaprogramming when the pair's types are programmatically inferred from other types. At then end, you usually have some form of "empty struct".

I would prefer std::pair for any "normal" use, unless you are into heavy template metaprogramming.

It's nothing but a structure with two variables under the hood.

I actually dislike using std::pair for function returns. The reader of the code would have to know what .first is and what .second is.

The compromise I use sometimes is to immediately create constant references to .first and .second, while naming the references clearly.

It is just as simple two elements tuple. It was defined in first version of STL in times when compilers were not widely supporting templates and metaprogramming techniques which would be required to implement more sophisticated type of tuple like Boost.Tuple.

It is useful in many situations. std::pair is used in standard associative containers. It can be used as a simple form of range std::pair<iterator, iterator> - so one may define algorithms accepting single object representing range instead of two iterators separately. (It is a useful alternative in many situations.)

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.

 
推荐文章