有什么std::pair
用,我为什么要使用它,它boost::compressed_pair
带来了什么好处?
10 回答
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; };
在这里,B
和C
具有相同的大小是可以的,即使sizeof(A)
不能为零。
因此boost::compressed_pair
,利用这种优化,如果它是空的,将在可能的情况下从该对中的一个或另一个类型继承。
所以astd::pair
可能看起来像(我省略了很多,ctors等):
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) 一样大。
您有时需要从一个函数返回 2 个值,并且为此创建一个类通常是矫枉过正的。
std:pair 在这些情况下会派上用场。
我认为 boost:compressed_pair 能够优化掉大小为 0 的成员。这对于库中的重型模板机制非常有用。
如果您确实直接控制类型,则无关紧要。
听到compressed_pair 关心几个字节听起来很奇怪。但是当考虑在哪里可以使用compressed_pair 时,它实际上可能很重要。例如,让我们考虑以下代码:
boost::function<void(int)> f(boost::bind(&f, _1));
在上述情况下使用compressed_pair 会突然产生很大的影响。如果 boost::bind 将函数指针和占位符存储_1
为自身或 astd::pair
本身的成员,会发生什么情况?好吧,它可能膨胀到sizeof(&f) + sizeof(_1)
. 假设函数指针有 8 个字节(对于成员函数来说并不罕见)并且占位符有一个字节(请参阅 Logan 的回答了解原因),那么绑定对象可能需要 9 个字节。由于对齐,这可能会在通常的 32 位系统上膨胀多达 12 个字节。
boost::function
鼓励其实现应用小对象优化。这意味着对于小型函子,直接嵌入在boost::function
对象中的小缓冲区用于存储函子。对于较大的仿函数,必须通过使用 operator new 来使用堆来获取内存。在 boost版本 1.34左右,决定采用这种优化,因为它被认为可以获得一些非常好的性能优势。
现在,这样一个小缓冲区的合理(但可能仍然很小)限制是 8 个字节。也就是说,我们非常简单的绑定对象不适合小缓冲区,并且需要存储 operator new。如果上面的绑定对象使用 a compressed_pair
,它实际上可以将它的大小减少到 8 个字节(或非成员函数指针通常为 4 个字节),因为占位符只不过是一个空对象。
因此,看起来只是为了几个字节而浪费大量精力实际上会对性能产生重大影响。
std::pair 对于 STL 中的其他几个容器类非常有用。
例如:
std::map<>
std::multimap<>
两者都存储 std::pairs 键和值。
在使用 map 和 multimap 时,您经常使用指向 pair 的指针来访问元素。
它是存储一对值的标准类。它被一些标准函数返回/使用,例如std::map::insert
.
boost::compressed_pair
声称更有效率:见这里
附加信息:当对的类型之一是空结构时, boost::compressed_pair 很有用。当对的类型以编程方式从其他类型推断时,这通常用于模板元编程中。最后,您通常会有某种形式的“空结构”。
我更喜欢 std::pair 用于任何“正常”使用,除非您从事繁重的模板元编程。
它只不过是一个具有两个变量的结构。
我实际上不喜欢使用 std::pair 来返回函数。代码的读者必须知道 .first 是什么以及 .second 是什么。
我有时使用的折衷方案是立即创建对 .first 和 .second 的常量引用,同时清楚地命名引用。
什么是 std::pair,我为什么要使用它?
它就像简单的两个元素元组一样。它是在STL的第一个版本中定义的,当时编译器没有广泛支持模板和元编程技术,而这些技术需要实现更复杂的元组类型,如Boost.Tuple。
它在许多情况下都很有用。std::pair
用于标准关联容器。它可以用作范围的一种简单形式std::pair<iterator, iterator>
- 因此可以定义接受单个对象表示范围的算法,而不是分别接受两个迭代器。(在许多情况下它是一个有用的替代方案。)
有时,您总是将两条信息一起传递,无论是作为参数,还是返回值,或其他。当然,您可以编写自己的对象,但如果它只是两个小的原语或类似的,有时一对似乎就可以了。