繁体   English   中英

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

[英]Can I prevent zero initialization of the elements in an array data member in a non-POD class?

非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

然后我添加了一个构造函数来为_payload进行显式值初始化并再次运行测试:

PayloadMessage() : _payload() {}

$ g++ -O3 test.cpp
$ time ./a.out
real    0m10.361s
user    0m3.582s
sys     0m5.797s

是的,具有显式初始化的第二个版本需要更长时间,因此我假设第一个版本没有进行初始化(它只是看起来那样)。 感谢你的帮助。

POD仅在使用() (C ++标准中为8.5 ()时显式初始化值,否则默认初始化。 POD的默认初始化意味着它对内存没有任何作用。 如果operator new返回零初始化内存,那么PayloadMessage的构造函数不会执行任何额外的工作。 出于好奇,您是否检查了PayloadMessage的构造函数的反汇编,以确定它是否实际上做了任何昂贵的事情?

没有理由将这个数组初始化为零:我认为你应该查看你的特定实现的文档(可能是调试选项?)。

您可以使用std::vectorpush_back (可选择使用reserve )吗? 这允许您在需要时准确构造对象。

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

编辑2:假设您当前的代码正常工作,您是否实际通过分析确认初始化实际上是代码中的瓶颈? 这可能严格地说是过早优化。

在编辑中回答你的问题“有没有人知道什么可能导致内存看起来被归零?”

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

无法在第一次访问时避免内存变为清零,但您可以使用自定义内存分配器来重用从操作系统请求的虚拟内存池。 这将允许后续请求避免清除。 保持虚拟内存与operator delete的默认行为相反,即将虚拟内存返回给操作系统以进行大量分配。 也可以在执行虚拟分配和解除分配时调整默认分配器的阈值,但这取决于系统。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM