在执行时加载常量,一次还是两次?

时间:2013-05-15 19:29:33

标签: c++

我对加载C ++生成的可执行文件感到有点困惑。我将一个巨大的常量字符串表放入目标可执行文件中。数据应嵌入可执行文件中(无外部文件)。

struct DataRecord
{
    unsigned char n1;
    unsigned char n2;
    std::string text;
};

static const DataRecord data[] = {
    {1, 2, "Hello"},
    {1, 3, "Hi"},
    {1, 4, "Bye"}
    .
    .
    VERY LONG LIST    
    .
    .
};

在运行代码时编译并生成代码后,可能会出现两种情况:

  1. 操作系统加载巨大的可执行文件(需要时间),然后运行程序,之后程序就可以使用数组data了。

  2. 操作系统加载巨大的可执行文件(需要时间),然后运行程序,之后程序必须创建表并加载字符串文字并构造那些std::string个对象(需要时间)

  3. 很明显,第二个比第一个慢。

    • 如何知道哪一个会发生?
    • 拥有大量嵌入数据的最佳方法是什么(权衡:速度和空间)?
    • 使用工具objcopy是否有用(我没有任何经验)?

    我正在使用gcc 4.7+,目标操作系统是Windows / Linux / Android(NDK)

2 个答案:

答案 0 :(得分:4)

在这种情况下,必须调用构造函数。示例中字符串的构造函数不能“在编译时完成”。 [编辑:由于std::string必须调用operator new()来分配内存(或者以其他方式分配内存,尽管对于短字符串可以避免这种情况,但是这个决定不太可能是充分推导出编译器可以“就地”构建正确的数据结构 - 结束编辑]

在这种特殊情况下,您可以使用const char *而不是std::string来避免构造,但是假设字符串不会被修改,这当然可能是一个延伸[并且如果在使用之前,你需要所有字符串都是std::string,并且你使用大表中的所有字符串,如果有的话,几乎没有任何好处]。

顺便说一下,(在大多数操作系统中)程序不会加载代码“所有代码都在一个大的去,需要很长时间”。相反,它加载“入口点”(在4KB的块中,这是4KB对齐的包含入口点的代码块)。其他所有东西都是“需求加载” - 也就是说,它是根据需要加载的。

答案 1 :(得分:1)

普通旧数据(POD)可以在编译和链接时准备并存储在可执行文件中,因此只需将其加载到内存中即可使用。但是,具有构造函数的类的任何成员数据都可能需要调用构造函数。

我使用Apple clang 4.0 for x86_64编译代码,检查生成的代码,并逐步完成部分执行。它调用字符串构造函数并调用malloc

理论上,一个积极的C ++实现可以将大部分工作转移到编译和链接时间,但是你通常应该期望像这样的数据将导致在程序启动时调用构造函数和内存分配。