std::pair
是什么,我为什么要使用它,以及boost::compressed_pair
有什么好处?
compressed_pair
使用模板技巧来节省空间。在 C++ 中,一个对象(小写字母 o)不能和另一个不同的对象有相同的地址。
因此,即使你有
struct A { };
A
的大小不会为0,否则:
A a1;
A a2;
&a1 == &a2;
会发生非法操作,因为变量持有一个不被允许的值。
但是很多编译器都会执行所谓的“空基类优化”:
struct A { };
struct B { int x; };
struct C : public A { int x; };
这里,即使sizeof(A)
不能为零,B
和C
具有相同的大小也是可以的。
因此,boost::compressed_pair
利用了这个优化,在可能的情况下,如果一对类型中有一个为空,它将继承自其中一个类型。
所以,一个 std::pair
可能看起来像这样(省略了许多内容,如构造函数等):
template<typename FirstType, typename SecondType>
struct pair {
FirstType first;
SecondType second;
};
这意味着如果FirstType
或SecondType
之一是A
,则您的pair<A,int>
必须大于sizeof(int)
。
但是,如果您使用compressed_pair
,它生成的代码将类似于:
struct compressed_pair<A,int> : private A {
int second_;
A first() { return *this; }
int second() { return second_; }
};
而 compressed_pair<A,int>
的大小只有 sizeof(int)。
听到压缩对要注意几个字节可能听起来很奇怪。但是当考虑到压缩对可以使用的地方时,这实际上可能非常重要。例如,让我们考虑以下代码:
boost::function<void(int)> f(boost::bind(&f, _1));
现在,对于这样一个小缓冲区来说,一个合理的(尽管可能仍然很小)限制应该是8个字节。也就是说,我们相当简单的绑定对象不适合放入小缓冲区中,并且需要使用operator new进行存储。如果上述绑定对象使用了compressed_pair
,它实际上可以将其大小减小到8个字节(对于非成员函数指针通常为4个字节),因为占位符只是一个空对象。
因此,看起来只是为了节省一些字节而浪费了很多思考,实际上可能会对性能产生重大影响。
std::pair是什么,我为什么要使用它?
它只是一个简单的两个元素的元组。它是在STL的第一个版本中定义的,当时编译器不广泛支持模板和元编程技术,这些技术需要实现更复杂类型的元组,如Boost.Tuple。
它在许多情况下都很有用。 std::pair
在标准关联容器中使用。它可以被用作范围的简单形式 std::pair<iterator, iterator>
- 因此可以定义接受单个表示范围的对象的算法,而不是分别定义两个迭代器。
(在许多情况下,这是一个有用的替代品。)
std::pair在STL中的其他一些容器类中非常方便。
例如:
std::map<>
std::multimap<>
这两者都存储键和值的 std::pair。
当使用 map 和 multimap 时,通常使用指向 pair 的指针来访问元素。
这是用于存储一对值的标准类。它被一些标准函数(如std::map::insert
)返回/使用。
boost::compressed_pair
声称更加高效:点击此处了解更多信息。
附加信息:当一对中的一个类型是空结构体时,boost::compressed_pair非常有用。在模板元编程中经常使用此功能,当从其他类型程序化推断出一对的类型时。最后,通常会得到某种形式的“空结构体”。
除非您进行大量的模板元编程,否则我更喜欢std::pair用于任何“正常”用途。
实际上这只是一种带有两个变量的结构。
我不喜欢在函数返回时使用std::pair。代码的读者需要知道first和second分别代表什么意思。
有时我会做一个妥协,立即创建对first和second的常量引用,并清晰地命名这些引用。