题
什么是 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; };
在这里,很好 B
和 C
具有相同的尺寸,即使 sizeof(A)
不可能为零。
所以 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) 一样大。
有时您需要从函数返回 2 个值,而为此创建一个类通常是多余的。
std:pair 在这些情况下会派上用场。
我认为 boost:compressed_pair 能够优化掉大小为 0 的成员。这对于图书馆中的重型模板机械最有用。
如果您直接控制类型,那就无关紧要了。
听到压缩对关心几个字节听起来很奇怪。但当人们考虑在哪里可以使用compressed_pair时,它实际上很重要。例如,让我们考虑一下这段代码:
boost::function<void(int)> f(boost::bind(&f, _1));
在上述情况下使用压缩对可能会突然产生很大的影响。如果 boost::bind 存储函数指针和占位符会发生什么 _1
作为其本身或某个组织的成员 std::pair
在自身?好吧,它可能会膨胀到 sizeof(&f) + sizeof(_1)
. 。假设函数指针有 8 个字节(对于成员函数来说并不罕见)并且占位符有 1 个字节(请参阅 Logan 的回答了解原因),那么我们可能需要 9 个字节用于绑定对象。由于对齐,这在通常的 32 位系统上可能会膨胀多达 12 个字节。
boost::function
鼓励其实现应用小对象优化。这意味着对于 小的 函子,一个直接嵌入到的小缓冲区 boost::function
对象用于存储函子。对于较大的函子,必须通过使用运算符 new 来使用堆来获取内存。周围升压 1.34版, ,决定采用 本次优化, ,因为人们认为可以获得一些非常好的性能优势。
现在,对于如此小的缓冲区来说,合理的(但可能仍然很小)限制是 8 个字节。也就是说,我们非常简单的绑定对象将 不是 适合小缓冲区,并且需要存储operator new。如果上面的绑定对象使用 compressed_pair
, ,它实际上可以将其大小减少到 8 个字节(对于非成员函数指针通常为 4 个字节),因为占位符只不过是一个空对象。
因此,看似仅仅为了几个字节而浪费大量思考实际上可能会对性能产生重大影响。
它是用于存储一对值的标准类。它由一些标准函数返回/使用,例如 std::map::insert
.
boost::compressed_pair
声称更高效: 看这里
std::pair 对于 STL 中的其他几个容器类非常有用。
例如:
std::map<>
std::multimap<>
两者都存储 std:: 键和值对。
使用映射和多重映射时,您经常使用指向对的指针来访问元素。
附加信息:当对的类型之一是空结构时, boost::compressed_pair 很有用。当以编程方式从其他类型推断出对的类型时,这通常在模板元编程中使用。最后,您通常会得到某种形式的“空结构”。
我更喜欢 std::pair 进行任何“正常”使用,除非您喜欢繁重的模板元编程。
它只不过是一个在幕后有两个变量的结构。
我实际上不喜欢使用 std::pair 来返回函数。代码的读者必须知道什么是 .first 和什么是 .second。
我有时使用的折衷方案是立即创建对 .first 和 .second 的常量引用,同时明确命名引用。
有时,您总是一起传递两条信息,无论是作为参数,还是作为返回值,或者其他什么。当然,您可以编写自己的对象,但如果它只是两个小的基元或类似的对象,有时一对似乎就可以了。