运算符new将内存初始化为零

问题描述 投票:59回答:4

有这样的代码:

#include <iostream>

int main(){
  unsigned int* wsk2 = new unsigned int(5);
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  delete wsk2;
  wsk2 = new unsigned int;
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  return 0;
}

结果:

wsk2: 0x928e008 5
wsk2: 0x928e008 0

我已经读过new没有用零初始化内存。但似乎它确实如此。它是如何工作的?

c++ memory-management
4个回答
157
投票

有两个版本:

wsk = new unsigned int;      // default initialized (ie nothing happens)
wsk = new unsigned int();    // zero    initialized (ie set to 0)

也适用于数组:

wsa = new unsigned int[5];   // default initialized (ie nothing happens)
wsa = new unsigned int[5](); // zero    initialized (ie all elements set to 0)

在回答下面的评论。

嗯......你确定new unsigned int[5]()将整数归零吗?

显然是的:

[C ++ 11:5.3.4 / 15]:创建类型为T的对象的new-expression初始化该对象,如下所示:如果省略new-initializer,则默认初始化对象(8.5);如果没有执行初始化,则该对象具有不确定的值。否则,根据8.5的初始化规则解释new-initializer以进行直接初始化。

#include <new>
#include <iostream>


int main()
{
    unsigned int   wsa[5] = {1,2,3,4,5};

    // Use placement new (to use a know piece of memory).
    // In the way described above.
    // 
    unsigned int*    wsp = new (wsa) unsigned int[5]();

    std::cout << wsa[0] << "\n";   // If these are zero then it worked as described.
    std::cout << wsa[1] << "\n";   // If they contain the numbers 1 - 5 then it failed.
    std::cout << wsa[2] << "\n";
    std::cout << wsa[3] << "\n";
    std::cout << wsa[4] << "\n";
}

结果:

> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix
> g++ t.cpp
> ./a.out
0
0
0
0
0
>

19
投票

operator new不保证将内存初始化为任何东西,并且在没有new-initializer的情况下分配unsigned int的new-expression会使对象具有不确定的值。

读取未初始化对象的值会导致未定义的行为。未定义的行为包括评估零值而没有不良影响但可能导致任何事情发生,因此您应该避免导致它。

在C ++ 11中,使用的语言是分配的对象是默认初始化的,对于非类类型意味着不执行初始化。这与C ++ 03中default-initialized的含义不同。


4
投票

对于一些编译器,new的调试版本将初始化数据,但肯定没有什么可以依赖。

存储器也可能从之前的使用中获得0。不要假设删除和新内存之间没有任何内容发生。在背景中可能会有一些你从未注意到的事情。此外,相同的指针值可能不是相同的物理内存。内存页面被移动并被分页输入。指针可能被映射到一个完全不同的位置。

底线:如果您没有专门初始化内存位置,那么您可以不假设其内容。在使用内存之前,内存管理器甚至可能不会分配特定的物理内存位置。

现代内存管理非常复杂,但作为一名C ++程序员,你并不在乎(主要是‡)。遵守规则,你不会遇到麻烦。

‡如果您正在优化以减少页面错误,您可能会在意。


3
投票

这不是operator new,那是new运营商。实际上有很大的不同!区别在于operator new是一个返回原始内存的函数;当你使用new运算符时,它会为你调用一个构造函数。这是构造函数设置int的值,而不是operator new

© www.soinside.com 2019 - 2024. All rights reserved.