我才刚刚开始使用C ++,我想养成一些好习惯。如果我刚刚int
用new
运算符分配了一个类型数组,如何将它们全部初始化为0而又不自己遍历它们呢?我应该使用memset
吗?有没有一种“ C ++”的方式来做到这一点?
&vector[0]
。
我才刚刚开始使用C ++,我想养成一些好习惯。如果我刚刚int
用new
运算符分配了一个类型数组,如何将它们全部初始化为0而又不自己遍历它们呢?我应该使用memset
吗?有没有一种“ C ++”的方式来做到这一点?
&vector[0]
。
Answers:
这是C ++的一个鲜为人知的鲜为人知的功能(事实证明,还没有人给出这个答案),但是它实际上具有用于对数组进行值初始化的特殊语法:
new int[10]();
请注意,您必须使用空括号-例如,您不能使用(0)
或其他任何内容(这就是为什么它仅对值初始化有用)的原因。
ISO C ++ 03 5.3.4 [expr.new] / 15明确允许这样做,它表示:
创建一个对象类型的new表达式
T
按如下方式初始化该对象:...
- 如果new-initializer的形式为
()
,则该项目将被值初始化(8.5);
并且不限制允许使用的类型,而该(expression-list)
格式又受同一节中其他规则的明确限制,因此不允许使用数组类型。
new int[10] {}
。您还可以提供以下值进行初始化:new int[10] {1,2,3}
假设您确实确实想要一个数组而不是std :: vector,那么“ C ++方式”就是这样
#include <algorithm>
int* array = new int[n]; // Assuming "n" is a pre-existing variable
std::fill_n(array, n, 0);
但是请注意,实际上,这实际上仍然是一个将每个元素分配为0的循环(实际上并没有另一种方式,除非有硬件级别的支持的特殊体系结构)。
分配固有类型数组的方法有很多,所有这些方法都是正确的,尽管选择哪种方法取决于...
手动初始化循环中的所有元素
int* p = new int[10];
for (int i = 0; i < 10; i++)
{
p[i] = 0;
}
使用std::memset
功能<cstring>
int* p = new int[10];
std::memset(p, 0, sizeof(int) * 10);
使用std::fill_n
来自的算法<algorithm>
int* p = new int[10];
std::fill_n(p, 10, 0);
使用std::vector
容器
std::vector<int> v(10); // elements zero'ed
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
int array[SIZE] ={1,2,3,4,5,6,7};
符号,则可以使用void rotateArray(int (& input)[SIZE], unsigned int k);
我的函数声明,使用第一个约定时会是什么?有什么建议吗?
std::memset
是错误的-您传递了10,似乎期望字节数-请参见en.cppreference.com/w/cpp/string/byte/memset。(我认为这很好地说明了为什么在可能的情况下应该避免这样的低级构造。)
如果您分配的内存是带有构造函数的类,该构造函数执行了一些有用的操作,则new运算符将调用该构造函数并使您的对象初始化。
但是,如果要分配POD或没有初始化对象状态的构造函数的东西,则不能在一个操作中分配内存并使用new运算符初始化该内存。但是,您有几种选择:
1)改用堆栈变量。您可以一步分配和默认初始化,如下所示:
int vals[100] = {0}; // first element is a matter of style
2)使用 memset()
。请注意,如果您要分配的对象不是POD,则对其进行内存设置是一个坏主意。一个特定的示例是,如果您将一个具有虚函数的类设为memset,则会破坏该vtable并使对象处于无法使用的状态。
3)许多操作系统都有执行您想要的操作的调用-在堆上分配并将数据初始化为某种东西。Windows的例子是VirtualAlloc()
4)这通常是最好的选择。避免完全自己管理内存。您可以使用STL容器完成对原始内存的几乎所有处理,包括一次分配和初始化所有内存:
std::vector<int> myInts(100, 0); // creates a vector of 100 ints, all set to zero
就在这里:
std::vector<int> vec(SIZE, 0);
使用向量而不是动态分配的数组。好处包括不必费心显式删除数组(当向量超出范围时将其删除),并且即使抛出异常也将自动删除内存。
编辑:为了避免不打扰阅读以下评论的人造成进一步的低估,我应该更清楚地表明,这个答案并不表示向量始终是正确的答案。但是,与确保删除数组相比,它肯定是比“手动”更多的C ++方法。
现在使用C ++ 11,还有std :: array,它对恒定大小的数组进行建模(对可以增长的向量)。还有一个std :: unique_ptr,它管理动态分配的数组(可以与初始化结合使用,如对该问题的其他答案所述)。与手动处理指向数组的指针恕我直言相比,这些方法都是C ++方式。
std::vector
而不是动态分配的数组吗?在向量上使用数组有什么好处,反之亦然?
std::vector
。
vector
无论上下文如何,随处粘贴都称为“用C ++编写Java代码”。
std::fill
是一种方式。需要两个迭代器和一个值来填充区域。我认为,那或for循环将是更C ++的方式。
要将原始整数类型的数组专门设置为0 memset
是可以的,尽管这可能会引起注意。还考虑calloc
,尽管由于强制转换在C ++中使用有点不方便。
就我而言,我几乎总是使用循环。
(我不喜欢猜测人们的意图,但的确std::vector
是,在所有条件都相同的情况下,最好使用new[]
。)
您可以随时使用memset:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
memset
,但是我不确定这是否是解决问题的C ++方法。
10 * sizeof( *myArray )
比拥有更多的文档记录和更可靠的更改10 * sizeof( int )
。
通常,对于动态项目列表,请使用std::vector
。
通常,我将memset或循环用于原始内存动态分配,具体取决于我对代码区域的期望程度。