如何用C++中的new运算符初始化内存?

dre*_*lax 163 c++ memory-management initialization new-operator

我刚刚开始进入C++,我想养成一些好习惯.如果我刚刚int使用new运算符分配了一个类型的数组,我怎么能将它们全部初始化为0而不用自己循环遍历它们?我应该用memset吗?有没有"C++"方法呢?

Pav*_*aev 368

这是一个令人惊讶的鲜为人知的C++特性(事实证明,没有人将此作为答案),但它实际上有默认初始化数组的特殊语法(从技术上讲,它被称为"值 - 初始化"在标准中":

new int[10]();
Run Code Online (Sandbox Code Playgroud)

请注意,您必须使用空括号 - 例如,您不能使用(0)或任何其他表达式(这就是为什么这仅对默认初始化有用).

这是ISO C++ 03 5.3.4 [expr.new]/15明确允许的,它表示:

创建类型为T的对象的new-expression初始化该对象,如下所示:

...

  • 如果new-initializer的格式为(),则该项是值初始化的(8.5);

并且不限制允许此类型的类型,而T表单由同一部分中的其他规则明确限制,以使其不允许数组类型.

  • 在C++ 11中,您也可以使用统一初始化:`new int [10] {}`.您还可以使用以下命令提供值:`new int [10] {1,2,3}` (30认同)
  • 虽然我同意这是鲜为人知的,但我不能(完全)同意它真的非常令人惊讶——它是在 C++ 03 中添加的,大多数人似乎几乎忽略了它(因为这是为数不多的新事物之一它确实添加了)。 (2认同)
  • @Jerry:我必须承认我还不知道(可能是因为当我阅读标准时,已经是C ++ 03)。也就是说,我知道的所有实现都支持此功能,这一点非常了不起(我想这是因为实现起来如此琐碎)。 (2认同)
  • 是的,实现起来很简单。就所有而言,* ++ *“值初始化”是C ++ 03中的新功能。 (2认同)

Tyl*_*nry 25

假设你真的想要一个数组而不是std :: vector,那么"C++方式"就是这个

#include <algorithm> 

int* array = new int[n]; // Assuming "n" is a pre-existing variable

std::fill_n(array, n, 0); 
Run Code Online (Sandbox Code Playgroud)

但请注意,在引擎盖下,这实际上只是一个循环,将每个元素分配给0(实际上没有其他方法可以做到这一点,除非有一个具有硬件级支持的特殊架构).

  • 你可能会感到惊讶.我曾是.在我的STL(GCC和Dinkumware)上,std :: copy实际上变成了一个memcpy,如果它检测到它是用内置类型调用的.如果std :: fill_n使用memset,我不会感到惊讶. (4认同)
  • 不.使用"值初始化"将所有成员设置为0. (2认同)

mlo*_*kot 23

有许多方法可以分配一个内在类型的数组,所有这些方法都是正确的,尽管选择哪一种,取决于......

手动初始化循环中的所有元素

int* p = new int[10];
for (int i = 0; i < 10; i++)
{
    p[i] = 0;
}
Run Code Online (Sandbox Code Playgroud)

使用std::memset来自的功能<cstring>

int* p = new int[10];
std::memset(p, 0, 10);
Run Code Online (Sandbox Code Playgroud)

使用std::fill_n算法<algorithm>

int* p = new int[10];
std::fill_n(p, 10, 0);
Run Code Online (Sandbox Code Playgroud)

使用std::vector容器

std::vector<int> v(10); // elements zero'ed
Run Code Online (Sandbox Code Playgroud)

如果C++ 0x可用,则使用初始化列表功能

int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime
Run Code Online (Sandbox Code Playgroud)

  • 恐怕 `std::memset` 的例子是错误的 - 你传递了 10,它似乎期望字节数 - 请参阅 https://en.cppreference.com/w/cpp/string/byte/memset。(我认为这很好地说明了为什么人们应该尽可能避免这种低级构造。) (2认同)

Sri*_*tha 22

初始化普通动态数组的可能方法。根据您的要求选择一个。

int* x = new int[5];          // gv gv gv gv gv (gv - garbage value)
int* x = new int[5]();        // 0  0  0  0  0 
int* x = new int[5]{};        // 0  0  0  0  0  (Modern C++)
int* x = new int[5]{1,2,3};   // 1  2  3  0  0  (Modern C++)
Run Code Online (Sandbox Code Playgroud)


Joh*_*ing 7

如果要分配的内存是一个带有构造函数的类,它可以执行某些有用的操作,则new new将调用该构造函数并保持对象初始化.

但是,如果您正在分配POD或没有初始化对象状态的构造函数的东西,那么您无法在一次操作中分配内存并使用operator new初始化该内存.但是,您有几种选择:

1)改为使用堆栈变量.您可以在一个步骤中分配和默认初始化,如下所示:

int vals[100] = {0};  // first element is a matter of style
Run Code Online (Sandbox Code Playgroud)

2)使用memset().请注意,如果您要分配的对象不是POD,则设置它是个坏主意.一个具体的例子是如果你设置一个具有虚函数的类,你将吹掉vtable并使你的对象处于不可用状态.

3)许多操作系统都有调用你想做的事情 - 在堆上分配并将数据初始化为某些东西.Windows的例子就是VirtualAlloc()

4)这通常是最好的选择.避免必须自己管理内存.您可以使用STL容器来执行您对原始内存所做的任何事情,包括一次性分配和初始化:

std::vector<int> myInts(100, 0);  // creates a vector of 100 ints, all set to zero
Run Code Online (Sandbox Code Playgroud)


vil*_*pam 6

就在这里:

std::vector<int> vec(SIZE, 0);
Run Code Online (Sandbox Code Playgroud)

使用向量而不是动态分配的数组.好处包括不必费心删除数组(当向量超出范围时删除它)以及即使抛出异常也会自动删除内存.

编辑:为了避免那些懒得阅读下面评论的人进一步推销,我应该更清楚地说明这个答案并没有说向量总是正确的答案.但它肯定是一种比"手动"确保删除数组更多的C++方式.

现在使用C++ 11,还有std :: array模拟一个恒定大小的数组(vs能够增长的向量).还有std :: unique_ptr管理一个动态分配的数组(可以与初始化结合,如在这个问题的其他答案中回答的那样).其中任何一种都比手动处理指向数组的指针更加C++方式,恕我直言.

  • 这并没有真正回答被问到的问题. (11认同)
  • @villintehaspam:不,这不是一种C++方式.这是Java的方法.无论上下文如何都粘贴`vector`称为"用C++编写Java代码". (2认同)