代码之家  ›  专栏  ›  技术社区  ›  Mark Rajcok

我可以防止非POD类中数组数据成员中元素的零初始化吗?

  •  2
  • Mark Rajcok  · 技术社区  · 14 年前

    非POD派生类PayloadMessage包含一个数组数据成员(_payload),其元素在构造时似乎初始化为零。我不希望因为性能/效率的原因而发生这种情况——它是一个很大的数组。建议?(可能是新的位置?)我正在使用一个旧的g++编译器3.4.6。

    #include <iostream>
    class BaseMessage {
    public:
      enum CCC_MessageType {  START_THREAD, KILL_THREAD };
      CCC_MessageType _type;
      virtual ~BaseMessage() {}  // class has other non-POD class stuff
    };
    class PayloadMessage : public virtual BaseMessage {
    public:
      uint16_t _payload_length;
      uint8_t  _payload[3000];
    };
    int main(int argc, char* argv[]) {
      PayloadMessage* m = new PayloadMessage;
      size_t i = 0;
      for(; i < 3000; i++) { 
        std::cout << ' ' <<  static_cast<int>(m->_payload[i]); // all zeros, not what I want
      }
    }
    

    编辑: 好的,根据注释/答案和一些测试(如下所示),数组没有初始化。(是否有人知道是什么导致内存看起来为零?)

    为了进行性能测试,我将main()更改为:

    int main(int argc, char* argv[]) {
      PayloadMessage* m = new PayloadMessage;
      size_t i = 0;
      for(; i < 1400000; i++) {  // allocates just under 4GB, for 32-bit compatibility
        m = new PayloadMessage;
      }
    }
    

    然后编译并运行定时测试:

    $ g++ -O3 test.cpp
    $ time ./a.out
    real    0m7.068s
    user    0m1.393s
    sys     0m4.730s
    

    然后,我添加了一个构造函数来执行有效负载的显式值初始化,并再次运行测试:

    PayloadMessage() : _payload() {}
    
    $ g++ -O3 test.cpp
    $ time ./a.out
    real    0m10.361s
    user    0m3.582s
    sys     0m5.797s
    

    是的,显式初始化的第二个版本需要更长的时间,所以我假设第一个版本没有进行初始化(看起来就是这样)。谢谢大家的帮助。

    4 回复  |  直到 14 年前
        1
  •  4
  •   MSN    14 年前

    POD仅在使用时显式初始化值 () (8.5在C++标准中),否则,它是默认初始化的。POD的默认初始化意味着它不会对内存做任何操作。如果 operator new 正在返回零初始化内存,然后 PayloadMessage 没有做任何额外的工作。出于好奇,你检查了 付费消息 是构造器来确定它是否真的做了什么昂贵的事情?

        2
  •  3
  •   icecrime    14 年前

    这个数组不应该初始化为零:我认为您应该检查特定实现的文档(可能是调试选项?).

        3
  •  2
  •   Mark B    14 年前

    你能用吗 std::vector push_back (可选 reserve )相反呢?这允许您在需要时构造对象。

    编辑:这也消除了对长度变量的需要。

    EDIT2:假设您当前的代码工作正常,您是否通过分析确认了初始化实际上是代码中的一个瓶颈?这可能完全是一个过早的优化。

        4
  •  1
  •   Joe    8 年前

    在编辑中回答您的问题“是否有人知道是什么导致内存看起来为零?”

    您正在分配大量内存,因此operator new正在从操作系统请求新的虚拟内存块。作为一项安全功能,所有当前操作系统都确保在进程读取虚拟分配的内存之前将其清除。这是为了确保进程隔离,以便您无法读取以前写入到另一个进程并由另一个进程释放的内存。

    避免在第一次访问时将内存归零是不可能的,但是可以使用自定义内存分配器来重用从操作系统请求的虚拟内存池。这将允许随后的请求避免清除。保留虚拟内存与运算符delete的默认行为相反,后者是将虚拟内存返回到操作系统进行大量分配。在执行虚拟分配和释放时,也可以调整默认分配器的阈值,但这取决于系统。