我注意到std :: pair在尝试将其保存到二进制文件时会发生一件令人不快的事情:std :: pair与一个单词对齐。它在处理器效率方面可能很有用,但需要更多的存储空间,所以我想将对齐模式切换为1字节的std :: pair。我的编译器是MS VC ++ 2012。
#include <iostream>
int main( )
{
struct S_a { double a; size_t b; };
#pragma pack(1)
struct S_wa { double a; size_t b; };
std::cout << sizeof( size_t ) << '\n'; // 4
std::cout << sizeof( double ) << '\n'; // 8
std::cout << sizeof( std::pair< size_t, size_t > ) << '\n'; // 8
std::cout << sizeof( std::pair< double, size_t > ) << '\n'; // 16 - bad
std::cout << sizeof( S_wa ) << '\n'; // 12 - good
std::cout << sizeof( S_a ) << '\n'; // 16
std::cout << sizeof( std::pair< double, double > ) << '\n'; // 16
}
我试过这个,但它不起作用:
#pragma pack(1)
typedef std::pair< double, size_t > Q;
std::cout << sizeof( Q ) << '\n'; // 16
答案 0 :(得分:6)
std::pair
基本上减少到:
class xxx
{
T1 _t1;
T2 _t2;
};
两个成员的对齐由定义模板本身时的强制对齐定义,而不仅仅是在用于实例化实例时。
STL的Microsoft实现使用符号_CRT_PACKING
来定义用于所有STL组件的打包。默认情况下,打包设置为8.如果在包含定义std::pair
(<utility>
)的标题之前自己定义此符号,理论上可以覆盖打包并设置自己的标记。
请注意调用库或其他采用标准打包的代码时可能遇到的潜在问题。
答案 1 :(得分:4)
抱歉,pack
编译指示在这种情况下不适合您。你可以
#define _CRT_PACKING 1
#include <utility>
这可能会导致所有问题。其中之一是某些API,特别是低级API,期望数据以某种方式对齐。并非所有人都足够聪明,能够处理不是这样的情况;这可能导致毫不客气的崩溃。
如果你真的想要像这样序列化对象,请自己处理std::pair<U,V>
的序列化(仅限示例):
template<typename U, typename V>
void paircpy(char *dest, const std::pair<U, V> &pair) {
memcpy(buffer, &pair.first, sizeof(U));
memcpy(buffer + sizeof(U), &pair.second, sizeof(V));
}
您可能希望处理非memcpy
的数据类型的特殊情况。
对于任何严肃的项目,你真正应该做的是以可移植的方式进行序列化对象,以便它们可以检索并优雅地处理诸如浮点,签名数据类型的不同编码,指针之类的东西,数组,STL容器以及其他任何不可能或者不足以简单地转储对象内存的东西。
阅读C++ FAQ并开发自己的序列化模块,这些模块不仅仅是将对象的内存中表示转储到文件中。
或者,您可以使用预先打包的便携式解决方案来序列化数据类型,例如
答案 2 :(得分:0)
好吧,完全不同的'解决方案'可能是也可能不是一个好主意,但是嘿,如果它有效,我是谁阻止你知道。它提供了与其他答案相同的警告,但允许您挑选和选择毒药。
对您所关注的类型进行std::pair
的部分特化,使用该特定定义的pragma包,例如。对于char
和int
:
namespace std {
#pragma pack( /* ... whatever you want ... */ )
template<> struct pair<char,int> {
char first;
int second;
};
}
根据定义你可以触摸它,你可以影响包装。同样,如果你愿意为所有相关类型做这件事,这只是好事,并记住其他海报提到的警告。
并且您使用的库很少有机会疯狂并且决定在pair
中添加更多其他lib依赖的东西,但您可能不需要担心关于它