使用值初始化的数组对零初始化数据
Zero-initialize data using value-initialized array
下面的代码会正确地初始化从malloc
返回的内存吗?
#include <cstdlib>
#include <new>
int main()
{
char* p = new (std::malloc(10)) char[10]{};
}
是的,由于行末尾的{}
,只要malloc
不会从放置new
中失败,它将对内存进行零初始化。这里有一个替代版本,更完全地证明了这一点。
#include <iostream>
#include <cassert>
#include <new>
char mongo[10];
int main()
{
for (int i=0; i < 10; ++i)
mongo[i] = 'a';
char *p = new (mongo) char[10]{};
for (int i= 0; i < 10; ++i)
assert(p[i] == ' ');
}
由于p
的初始化明确清除了mongo
数组(由p
别名),因此该程序将运行并不打印任何内容。相反,如果我们省略该行末尾的{}
,程序将断言并终止。
请注意,在使用malloc
的版本中,您将必须显式地销毁对象——这是放置new
的部分职责,也是现代C++中为数不多的必须显式调用析构函数的情况之一。
如果您使用malloc()
分配内存,则必须发出相应的free(p)
,否则程序将泄漏内存。
房间里的大象
(感谢@TC指出灰色的大东西!)以下是直接来自标准的解释和示例(第5.3.4节):
示例:
new T
导致呼叫operator new(sizeof(T))
,
new(2,f) T
导致呼叫operator new(sizeof(T),2,f)
,
new T[5]
导致呼叫operator new[](sizeof(T)*5+x)
,并且CCD_ 19导致CCD_。
这里,x和y是表示数组分配开销的非负未指定值;新表达式的结果将从CCD_ 21返回的值偏移该量。此开销可应用于所有数组新表达式中,包括那些引用库函数运算符
new[](std::size_t, void*)
和其他放置分配函数的表达式。每次调用new时,开销的大小可能会有所不同。
换句话说,如果您对单个对象使用放置new
,一切都很好,没有插入的开销,但如果您通过放置new
分配数组,则可能会有开销,而且从一次调用到另一次调用,其大小甚至可能不相同。
这是一个非常非常糟糕的主意。
目前,布局数组new
和所有数组new
表达式一样,被允许添加未指定数量的开销。程序没有可移植的方法来知道这个开销是多少字节
因此,除非char[10]
的实现的数组分配开销为零,否则您的代码具有未定义的行为。
如果指针指向足够的内存来容纳所有数组元素加上未指定的开销量(这是一个很大的If,因为没有可移植的方法可以确定),那么表达式确实会对内存进行零初始化。
- 如何使用数据对象上的常量指针初始化类
- 如何在 malloc 内存中初始化非 POD 数据
- 内联静态数据的初始化
- 是否可以使用右值初始化数据成员?
- 构造函数正在初始化数据成员
- 初始化数据成员取决于构造函数中的条件
- openGL如何处理发送给它的空/未初始化数据?
- 如何在C 11中正确初始化数据成员
- 在具有初始化的声明中,是否可以使用对未初始化数据的引用
- 使用值初始化的数组对零初始化数据
- 在C++中,如果我们不在构造函数中初始化数据成员,那么类中数据成员的值会是多少
- 为什么我们需要构造函数 C++,我们可以通过函数(初始化数据或访问私有数据成员)来做同样的事情
- 正在初始化数据文件中的静态常量成员
- 用成员函数初始化数据成员
- 在不初始化数据的情况下调整 std::vector C++的大小<char>
- 尝试在构造函数中初始化数据成员,但失败.为什么
- 在c++中使用初始化列表初始化数据成员引用
- 如何创建一个可以初始化c++数据类型的类
- 当初始化数据类型char*和非char*时
- 代码是否被视为可移植可执行文件格式中的初始化数据,初始化数据和单元化数据之间的确切区别是什么