C ++:表现得像calloc的新调用?
-
03-07-2019 - |
题
我是否可以打电话给new
让它将内存归零calloc
?
解决方案
与某些人在答案中所说的相反, 是可能的。
char * c = new char[N]();
零会初始化所有字符(实际上,它称为值初始化。但是值初始化将为标量类型数组的所有成员进行零初始化)。如果这就是你所追求的。
值得注意的是,它也适用于没有用户声明的构造函数的(类数组)类型,在这种情况下,它们的任何成员都是值初始化的:
struct T { int a; };
T *t = new T[1]();
assert(t[0].a == 0);
delete[] t;
这不是某种延伸或其他什么。它在C ++ 98中的工作和行为也是一样的。就在那里它被称为默认初始化而不是值初始化。但是,对于标量或标量或POD类型的数组,在两种情况下均进行零初始化。
其他提示
不,但创建一个像calloc一样的新版本相当容易。它的实现方式与实现no-throw版本的新方法完全相同。
SomeFile.h
struct zeromemory_t{};
extern const zeromemory_t zeromemory;
void* __cdcel operator new(size_t cbSize, const zeromemory_t&);
SomeFile.cpp
const zeromemory_t zeromemory;
void* _cdecl operator new(size_t cbSize, const zeromemory_t&)
{
void *mem = ::operator new(cbSize);
memset(mem,0,cbSize);
return mem;
}
现在,您可以执行以下操作以获得零内存的新内容
MyType* pMyType = new (zeromemory) MyType();
此外,您还需要做其他有趣的事情,例如定义new [],这也很简单。
没有。甚至不要想做类似的事情:
YourClass *var = new YourClass;
memset(var, 0, sizeof(YourClass));
你最终可能会破坏你的VTABLE(如果你的班级有一个)。
我建议使用构造函数来清除类的内部存储器(变量)。
不。它总是默认初始化分配的项目,在基元的情况下什么都不做。您必须使用std :: uninitialized_fill_n调用或类似方法进行跟进。
您可以对运算符new
进行全局重载,并从calloc()
获取原始内存。这样在构造函数运行之前内存就会被擦除,所以那里没有问题。
任何覆盖new的类都不会得到你特殊的基于delete
的new_handler
,但是那个类应该正确地初始化自己。
不要忘记覆盖bad_alloc
和no_throw
以及数组版本......
类似的东西:
#include <exception> // for std::bad_alloc
#include <new>
#include <stdlib.h> // for calloc() and free()
void* operator new (size_t size)
{
void *p=calloc(size, 1);
if (p==0) // did allocation succeed?
throw std::bad_alloc();
return p;
}
void operator delete (void *p)
{
free(p);
}
void* operator new[] (size_t size)
{
void *p=calloc(size, 1);
if (p==0) // did allocation succeed?
throw std::bad_alloc();
return p;
}
void operator delete[] (void *p)
{
free(p);
}
请注意,这些简单版本并不完全是它们应该是 - <=>运算符应该在一个循环中运行,调用<=>(如果安装了一个)并且只抛出<=>异常,如果有的话没有<=>。或类似的东西,我将不得不查找并稍后更新。
哦,您可能还想覆盖<=>版本。
我使用宏:
#define newclear(TYPE) new(calloc(sizeof(TYPE), 1)) TYPE();
使用它:
Whatever* myWhatever = newclear(Whatever);
(这使用<!> quot; placement new <!>;像其他一些解决方案一样)
不。你必须手动将内存归零。请记住,new
不仅仅是分配内存,还包括通过构造函数初始化。这是calloc
在C中很方便的地方(它没有初始化函数)。您可以自由地在<=>上编写包装器,甚至可以使用<=>,但是对于非POD对象,大多数情况下这都没有多大意义。
如果你不坚持使用new
,你可以简单地使用vector:vector<char> buffer; buffer.resize(newsize);
,内容将被归零。
class MyClass {
public:
void* operator new(size_t bytes) {
return calloc(bytes, 1);
}
}
如果您愿意,可以覆盖全局新操作符。
你可以说:
vector <char> v( 100, 0 );
使用new创建一个包含100个字符的连续数组,并将它们全部初始化为零。然后,您可以使用vector的[]运算符或执行以下操作来访问数组:
char * p = &v[0];
p[3] = 42;
请注意,这也使您无需调用delete来释放已分配的内存。
是。
int* p_scalar = new int(5);//Does not create 5 elements, but initializes to 5
对于数组,您可以使用类似memset的内容。对于Windows,使用ZeroMemory或SecureZeroMemory。
编辑:请参阅@ litb的帖子,他展示了如何使用非直接初始化(如上所述)为数组初始化为0。