我刚刚开始进入C ++,我想养成一些好习惯。如果我刚刚使用int
运算符分配了new
类型的数组,那么如何将它们全部初始化为0而不自行循环遍历它们?我应该使用memset
吗?是否有“C ++”方法可以做到这一点?
答案 0 :(得分:342)
这是一个令人惊讶的鲜为人知的C ++特性(事实证明,没有人将此作为答案),但它实际上有默认初始化数组的特殊语法(从技术上讲,它被称为标准中的“价值初始化”:
new int[10]();
请注意,必须使用空括号 - 例如,您不能使用(0)
或任何其他表达式(这就是为什么这仅对默认初始化有用)。
ISO C ++ 03 5.3.4 [expr.new] / 15明确允许这样做:
创建类型为T的对象的new-expression初始化该对象,如下所示:
...
- 如果new-initializer的格式为(),则该项值已初始化(8.5);
并不限制允许使用此类型的类型,而(expression-list)
表单则由同一部分中的其他规则明确限制,以使其不允许数组类型。
答案 1 :(得分:24)
假设你真的想要一个数组而不是std :: vector,那么“C ++方式”就是这个
#include <algorithm>
int* array = new int[n]; // Assuming "n" is a pre-existing variable
std::fill_n(array, n, 0);
但请注意,在实际应用中,这实际上只是一个将每个元素分配给0的循环(实际上没有其他方法可以做到这一点,除非有特殊架构支持硬件级别)。
答案 2 :(得分:20)
有许多方法可以分配一个内在类型的数组,所有这些方法都是正确的,尽管选择哪一个,取决于...
手动初始化循环中的所有元素
int* p = new int[10];
for (int i = 0; i < 10; i++)
{
p[i] = 0;
}
使用<cstring>
std::memset
功能
int* p = new int[10];
std::memset(p, 0, 10);
使用<algorithm>
std::fill_n
算法
int* p = new int[10];
std::fill_n(p, 10, 0);
使用std::vector
容器
std::vector<int> v(10); // elements zero'ed
如果C++0x可用,请使用initializer list功能
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
答案 3 :(得分:7)
如果你要分配的内存是一个带有构造函数的类,它会执行一些有用的操作,new new将调用该构造函数并保持对象的初始化。
但是如果你正在分配一个POD或没有构造函数初始化对象状态的东西,那么就不能在一次操作中分配内存并用operator new初始化那个内存。但是,您有几种选择:
1)改为使用堆栈变量。您可以一步分配和default-initialize,如下所示:
int vals[100] = {0}; // first element is a matter of style
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
答案 4 :(得分:6)
是的,有:
std::vector<int> vec(SIZE, 0);
使用向量而不是动态分配的数组。好处包括不必费心删除数组(当向量超出范围时删除它),并且即使抛出异常也会自动删除内存。
编辑:为了避免那些不愿意阅读下面评论的人进一步推销,我应该更清楚地说明这个答案并没有说矢量总是正确的答案。但它肯定是一种比“手动”确保删除数组更多的C ++方式。
现在使用C ++ 11,还有std :: array模拟一个恒定大小的数组(vs能够增长的向量)。还有std :: unique_ptr管理一个动态分配的数组(可以与初始化结合,如在这个问题的其他答案中回答的那样)。其中任何一种都比手动处理指向数组的指针更加C ++方式,恕我直言。
答案 5 :(得分:2)
std::fill
是一种方式。使用两个迭代器和一个值来填充区域。那个,或者for循环,(我想)是更多的C ++方式。
具体来说,为了将原始整数类型的数组设置为0,memset
很好,尽管它可能会引起人们的注意。还要考虑calloc
,尽管由于演员而使用C ++有点不方便。
就我而言,我几乎总是使用循环。
(我不想第二次猜测人们的意图,但std::vector
确实是,所有条件都相同,优于使用new[]
。)
答案 6 :(得分:1)
你总是可以使用memset:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
答案 7 :(得分:0)
对于 c++,使用 std::array<int/*type*/, 10/*size*/>
而不是 c 样式数组。这在 c++11 标准中可用,这是一个很好的做法。有关标准和示例,请参见 here。如果您出于某些原因想坚持使用旧的 c 样式数组,有两种可能的方法:
int *a = new int[5]();
此处将括号留空,否则会出现编译错误。这将初始化分配数组中的所有元素。这里如果不使用括号,它仍然会用零初始化整数值,因为 new 将调用构造函数,在本例中为 int()
。int *a = new int[5] {0, 0, 0};
这在 c++11 标准中是允许的。在这里,您可以使用您想要的任何值初始化数组元素。在这里确保您的初始化列表({} 中的值)大小不应大于您的数组大小。小于数组大小的初始化列表大小没问题。数组中剩余的值将被初始化为 0。答案 8 :(得分:0)
初始化普通动态数组的可能方法。根据您的要求选择一个。
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++)
答案 9 :(得分:-1)
通常,对于项目的动态列表,您使用std::vector
。
通常我使用memset或循环来进行原始内存动态分配,具体取决于我预期将来代码区域的变量。