41

Is there a call I can make to new to have it zero out memory like calloc?

banarun
  • 2,305
  • 2
  • 23
  • 40
nivnad
  • 696
  • 1
  • 5
  • 10

11 Answers11

78

Contrary what some are saying in their answers, it is possible.

char * c = new char[N]();

Will zero initialize all the characters (in reality, it's called value-initialization. But value-initialization is going to be zero-initialization for all its members of an array of scalar type). If that's what you are after.

Worth to note that it does also work for (arrays of) class-types without user declared constructor in which case any member of them is value initialized:

struct T { int a; };
T *t = new T[1]();
assert(t[0].a == 0);
delete[] t;

It's not some extension or something. It worked and behaved the same way in C++98 too. Just there it was called default initialization instead of value initialization. Zero initialization, however, is done in both cases for scalars or arrays of scalar or POD types.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    I learn something new each day from your posts! BTW, do you know why new[N](42) is not allowed? –  Apr 30 '09 at 19:06
  • T() is a special form: value-initialization or (what it was in c++98) default-initialization T(42), though, is direct initialization, and doesn't work for arrays – Johannes Schaub - litb Apr 30 '09 at 19:12
  • This is the specific scenario I was looking for, but all these other answers are great too! – nivnad Apr 30 '09 at 19:13
  • Is this true even under the C++98 standard which does not have value initialization (or is it default initialization that C++98 doesn't have)? I've written about that differences between C++98 and C++03 value/default initialization, but I honestly can't remember the details without looking it up (which I'm either too lazy or unable to do at the moment). – Michael Burr Apr 30 '09 at 19:13
  • Michael, yes i remember your post since it taught me value-initializations which i hadn't known before :) The same is true for c++98. But in case of a non-POD without user declared ctor, c++98 won't do any zero/value initializations of members, but instead delegate to the default constructor and leave members uninitialized. – Johannes Schaub - litb Apr 30 '09 at 19:16
  • 1
    Warning: this does NOT work for VC6. I've tried to compile on VC6 Debug builds, and it does NOT initialize the variables - treated just like c = new char[N]. – Francis Apr 30 '09 at 19:47
  • Many other things won't work on VC6 either. If you need a C++ compiler, better use a new version of it (recent releases of VC++ are gratis (express editions)) – Johannes Schaub - litb Apr 30 '09 at 20:01
  • I'm ok if some syntax does not work (i.e., compile failure) for VC6; but if something will get different results (and hard to be noticed), I'll prevent using it. Still many people & projects in this world is using VC6. – Francis Apr 30 '09 at 20:14
  • After looking at my notes, I'm reminded that the parens should make the new operator perform zero-initialization on POD types. If VC6 isn't doing this, then as litb mentions that looks to be non-conformant behavior (even for C++98). However, in VC6's defense, this whole area of initialization behavior of the new operator is incredibly convoluted and confusing in the details. – Michael Burr Apr 30 '09 at 20:23
  • 3
    Not to mention that VC6 actually slightly predates the C++98 standard :-) –  Apr 30 '09 at 21:00
11

No but it's fairly easy to create a new version that acts like calloc. It can be done in much the same way that the no-throw version of new is implemented.

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;
}

Now you can do the following to get new with zero'd memory

MyType* pMyType = new (zeromemory) MyType();

Additionally you'd need to do other fun things like define new[] which is fairly straight forward as well.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 2
    Just to point out the official name for this is placement new. If danvin wants more info on the subject. Can also be used for creating object caches ( think linux kernel slab cache ) – Robert S. Barnes Apr 30 '09 at 18:54
  • 2
    s/opeartor/operator/ ;) Might want to put as a warning, make sure to instantiate `const zeromemory_t zeromemory;` in exactly one compilation unit. – ephemient Apr 30 '09 at 20:13
  • @ephemient, Fixed the misspell. Curious, how could the value as defined only in a .cpp file be included in more than one compilation unit? – JaredPar Apr 30 '09 at 20:21
  • What I meant is: if you #include "SomeFile.h" in multiple .cpp files, you should only write "const zeromemory_t zeromemory;" in one .cpp file -- no more, no less -- if they're going to be linked together. – ephemient Apr 30 '09 at 22:01
  • @ephemient, gotcha. I meant for SomeFile.h and SomeFile.cpp to be a pair that was only done once. Probably should have called it AllocUtil.h and AllocUtil.cpp or the like to make it clearer – JaredPar Apr 30 '09 at 22:05
4

No. Also don't even think of doing something like:

YourClass *var = new YourClass;
memset(var, 0, sizeof(YourClass));

You could end up trashing your VTABLE (if your class has one).

I would recommend using constructors to clear the internal memory (variables) of your class.

Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
  • 3
    I dunno; if he really wants to shoot himself in the foot that badly, is it ethical to stop him? :-) – Paul Sonier Apr 30 '09 at 18:47
  • Definitely allocate and set your memory inside your class. Don't rely on memset. It works in many cases, but it's "undefined" in the spec. – Simon Gillbee Apr 30 '09 at 18:48
2

Nope. It will always default-initialize the allocated item(s), which in the case of primitives does nothing. You'll have to follow it up with a std::uninitialized_fill_n call or similar.

Promit
  • 3,497
  • 1
  • 20
  • 29
2

You could do a global overload of operator new and have it grab the raw memory from calloc(). This way the memory gets wiped before constructors get to run so there's no problems there.

Any class that overrides new on its own will not get your special calloc()-based new, but then that class should be initializing itself correctly anyway.

Don't forget to override both new and delete and the array versions...

Something like:

#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); 
}

Note that these simple versions aren't quite exactly what they should be - the new operator should run in a loop calling the new_handler (if one is installed) and only throwing the bad_alloc exception if there is no new_handler. Or something like that, I'll have to look it up and update later.

Oh, and you might want to also override the no_throw version as well.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
1

i use a macro:

#define newclear(TYPE) new(calloc(sizeof(TYPE), 1)) TYPE();

to use it:

Whatever* myWhatever = newclear(Whatever);

(this uses "placement new" like some other solutions here)

Christian Specht
  • 35,843
  • 15
  • 128
  • 182
0

No.You have to manually zero the memory out. Remember, new is not just about allocating memory, but also about initializing via constructors. This is where calloc is handy in C (which does not have initializer functions). You are free to write a wrapper over new or even use calloc, but most of the time for non-POD objects this doesn't make much sense.

dirkgently
  • 108,024
  • 16
  • 131
  • 187
0

if you don't insist using new, you can simply use vector: vector<char> buffer; buffer.resize(newsize); and the content will be zeroed.

Francis
  • 11,388
  • 2
  • 33
  • 37
0

Yes.

int* p_scalar = new int(5);//Does not create 5 elements, but initializes to 5

For arrays you can use something like memset. For windows use ZeroMemory or SecureZeroMemory.

Edit: Please see @litb's post, he shows how you can initialize to 0 for arrays using non direct initialization like above.

Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • try with array - it won't work (at least for ISO C++ - maybe some compilers with extension may allow it). – Francis Apr 30 '09 at 18:52
0
class MyClass {
    public:
    void* operator new(size_t bytes) {
        return calloc(bytes, 1);
    }
}

And you can override the global new operator if you like.

Unknown
  • 45,913
  • 27
  • 138
  • 182
0

You can say:

vector <char> v( 100, 0 );

which creates a contiguous array of 100 characters using new, and initialises them all to zero. You can then access the array with vector's [] operator, or by doing:

char * p = &v[0];
p[3] = 42;

Note this also frees you from having to call delete to free the allocated memory.