6

我注意到在尝试将 std::pair 保存到二进制文件时发生了一件不愉快的事情:std::pair 与一个单词对齐。它在处理器效率方面可能很有用,但需要更多存储空间,因此我想将对齐模式切换为 std::pair 的 1 字节。我的编译器是 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
4

3 回答 3

6

Astd::pair基本上归结为:

class xxx
{
   T1 _t1;
   T2 _t2;
};

两个成员的对齐由定义模板本身时有效的对齐定义,而不仅仅是在它用于实例化实例时。

STL 的 Microsoft 实现使用该符号_CRT_PACKING来定义用于所有 STL 组件的包装。默认情况下,包装设置为 8。如果您在包含定义std::pair( <utility>) 的标题之前自己定义此符号,您理论上可以覆盖包装并设置您自己的。

请注意在调用库或其他假定标准打包的代码时可能遇到的潜在问题。

于 2013-08-16T04:17:09.130 回答
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并开发您自己的序列化模块,这些模块不仅仅是将对象的内存表示转储到文件中。

或者,您可以使用预打包的便携式解决方案来序列化数据类型,例如

于 2013-08-16T04:25:11.160 回答
0

好吧,完全不同的“解决方案”可能是一个好主意,也可能不是一个好主意,但是嘿,如果它有效,我是谁来阻止你知道。它带有与其他答案相同的所有警告,但允许您挑选毒药。

std::pair对您关心的类型进行部分特化,使用该特定定义的 pragma 包,例如。对于charint

namespace std {
#pragma pack( /* ... whatever you want ... */ )
template<> struct pair<char,int> {
  char first;
  int second;
};
}

有了定义,你可以触摸它,你可以影响包装。同样,只有当您愿意为所有相关类型都这样做时,这才是好的,并记住其他海报提到的警告。

并且您使用的库很可能很疯狂,并决定将更多的东西放入pair该库的其余部分所依赖的东西中,但您可能不需要担心它

于 2013-08-16T04:44:46.813 回答