99

There is such code:

#include <iostream>

int main(){
  unsigned int* wsk2 = new unsigned int(5);
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  delete wsk2;
  wsk2 = new unsigned int;
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  return 0;
}

Result:

wsk2: 0x928e008 5
wsk2: 0x928e008 0

I have read that new doesn't initialize memory with zeroes. But here it seems that it does. How does it work?

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
scdmb
  • 15,091
  • 21
  • 85
  • 128
  • 2
    It doesn't, you'd have to use new unsigned int(). Reading uninitialized variables is UB, a 0 is certainly possible. – Hans Passant Sep 25 '11 at 15:58
  • 1
    As an aside, in practice lots of memory is zero anyway. If you do a plain malloc of a large chunk of memory, it's often all zero on some systems, or mostly zero on others. – Nicholas Wilson Sep 25 '11 at 16:11
  • 3
    @NicholasWilson: For most systems, this is only true when the memory came directly from the OS (for security reasons). When it came from memory cached by the allocator, it most likely contains whatever it did before it was free()d. This is also a reason why such bugs sometimes do not arise in testcases/unit tests, but only after a while of the "real" program running. Valgrind to the rescue here. – PlasmaHH Sep 26 '11 at 10:31
  • Yes. That's kind of my point. If you make a new variable and see that's it's zero, you can't straight away assume that something within your program has set it to zero. Since most memory comes ready-zeroed, it's probably still uninitialised. I think my remark is actually closer to answering the question than most of the answers below, because the questioner wanted to know why uninitialised memory might be zero. – Nicholas Wilson Sep 26 '11 at 10:57
  • Try allocating an array, setting all items to some nonzero value, then delete[] it and allocate it again - only the first item will be zeroed - others retain their values - which I think is a pecurliarity of the memory allocator (tested under Linux). – kyku Jul 30 '15 at 20:49
  • Related (asks for arrays): https://stackoverflow.com/questions/2204176/how-to-initialise-memory-with-new-operator-in-c – Aconcagua Nov 19 '18 at 07:09
  • `std::make_unique` has the same problem, fixed by `std::make_unique_for_overwrite` in C++20. – PBS Aug 12 '22 at 07:38

4 Answers4

240

There are two versions:

wsk = new unsigned int;      // default initialized (ie nothing happens)
wsk = new unsigned int();    // zero    initialized (ie set to 0)

Also works for arrays:

wsa = new unsigned int[5];   // default initialized (ie nothing happens)
wsa = new unsigned int[5](); // zero    initialized (ie all elements set to 0)

In answer to comment below.

Ehm... are you sure that new unsigned int[5]() zeroes the integers?

Apparently yes:

[C++11: 5.3.4/15]: A new-expression that creates an object of type T initializes that object as follows: If the new-initializer is omitted, the object is default-initialized (8.5); if no initialization is performed, the object has indeterminate value. Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct-initialization.

#include <new>
#include <iostream>


int main()
{
    unsigned int   wsa[5] = {1,2,3,4,5};

    // Use placement new (to use a know piece of memory).
    // In the way described above.
    // 
    unsigned int*    wsp = new (wsa) unsigned int[5]();

    std::cout << wsa[0] << "\n";   // If these are zero then it worked as described.
    std::cout << wsa[1] << "\n";   // If they contain the numbers 1 - 5 then it failed.
    std::cout << wsa[2] << "\n";
    std::cout << wsa[3] << "\n";
    std::cout << wsa[4] << "\n";
}

Results:

> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix
> g++ t.cpp
> ./a.out
0
0
0
0
0
>
Andreas Haferburg
  • 5,189
  • 3
  • 37
  • 63
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • And what about overloaded `new/new[]` operators? Will `new unsigned int[5]()` still zero-initialize the array even if it has a proprietary, completely unrelated implementation? – SomeWittyUsername Jun 08 '13 at 05:47
  • 2
    @icepack: The `operator new` is a user (developer) defined function it can do whatever it likes. The standard does not put constraints on what this function does. Just like `operator==` can do anything the user defines (it does not even need to return bool let alone test for equality (though it is bad form if it does not)). – Martin York Jun 08 '13 at 06:11
  • See: http://stackoverflow.com/questions/7194127/how-should-i-write-iso-c-standard-conformant-custom-new-and-delete-operators – Martin York Jun 08 '13 at 06:22
  • 1
    Thanks. Just to be clear: implementation of my proprietary allocator has nothing to do with zero-initialization and in case of using the `()` syntax the buffer will be zero-initialized without any relation to the type of allocated object and its constructor(s)? (And I suppose C++11 doesn't change anything in this aspect) – SomeWittyUsername Jun 08 '13 at 07:21
  • I am not sure. But I believe you will have to zero the memory manually I don't think the language is going to do anything for you (but I could be wrong). – Martin York Jun 08 '13 at 07:35
  • 1
    Ehm... are you _sure_ that `new unsigned int[5]()` zeroes the integers? – Lightness Races in Orbit Jun 16 '14 at 18:13
  • @LightnessRacesinOrbit: I was at the time. Have not looked at the standard as much recently. But I have added code that strongly suggested it works as described. – Martin York Jun 16 '14 at 23:15
  • @Loki: http://stackoverflow.com/a/24248894/560648 :) Your placement new example is great, though; I should have used that. – Lightness Races in Orbit Jun 16 '14 at 23:18
  • @MartinYork why is wsa modified? is it passed by reference to the new operator? I really couldnt find anything on arguments being passed to the new operator aside (nothrow), how does that work? – J3STER Jan 31 '18 at 09:45
  • 1
    @J3STER Passing a pointer with the new call is called placement new. See `8.3.4 New`. Why was it modified. Because we are forcing value-initialization. See `11.6 Initializers`. Note we are passing a pointer to the new operator. The value of `wsa` is NOT changed it is the address that is pointed at that is changed. – Martin York Jan 31 '18 at 17:18
  • What am I missing? How can this possibly the answer, if the line that produces the zero is `new unsigned int` and **not** `new unsigned int()`. (I know that reading the result of the second line is UB, I'm just asking, why this answer, that doesn't explain the question it got accepted and upvoted instead of e.g. CBBailey's answer) – MikeMB Apr 11 '19 at 08:10
  • @MikeMB You would have to ask the people that voted. But I would say is because it not only answers the question (`default initialized (ie nothing happens)`) but additionally provides extra relevant information that is useful to all programmers. How to zero initialize the memory and how it works with arrays. The point of SO is not just to answer the specific question asked but provide goo additional information. – Martin York Apr 11 '19 at 17:12
  • @MartinYork: But your answer doesn't answer the question (namely, "why does the memory get zero initialized even though no braces are used") at all. – MikeMB Apr 11 '19 at 18:22
  • @MikeMB The question is based on a false premise (that memory is being modified) so you can't answer that question. You have to explain what is happening. What is happening is: `default initialized (ie nothing happens)`. It obviously answered the OP question as he marked the answer with a tick (so it solved his question). – Martin York Apr 11 '19 at 18:58
  • @MikeMB But why are you asking question like this. If you think there is something missing from the answer then you should be editting the answer and adding the information that is missing. You have more than enough reputation to do this. This is a collaborative site. We try and make the answers as useful to as many people as possible. If you can make the answer better you are supposed to. – Martin York Apr 11 '19 at 19:01
  • @MartinYork: My question was litterally "what am I missing?" Before I start modifying a highly rated and accepted answer because I **think** it is missing the point, I'm trying to make sure it is not me who is missing the point. Now, the op wrote I have read that "new doesn't initialize memory with zeroes" yet, this is apparently what happens according to his tests and he asks why that is. Your answer just repeats what the OP already knows: "plain new" isn't supposed to do anything, but - as far as I can tell - you are not answering the question of why does the program behave the way it does? – MikeMB Apr 11 '19 at 19:29
  • *"The question is based on a false premise (that memory is being modified) so you can't answer that question."* Based on the program output it is being modified. – MikeMB Apr 11 '19 at 19:29
  • @MikeMB Because there are two vaiants. One variant (as used by the OP) does not change memory: `default initialized (ie nothing happens)` and then the second variant that allows you to make sure that the memory is initialized `zero initialized (ie set to 0)` (which is a useful thing to know that they did not know but I provided the information in addition). – Martin York Apr 11 '19 at 21:22
  • @MikeMB: Feel free to modify. As far as I am concerned the discussion is over. – Martin York Apr 11 '19 at 21:24
23

operator new is not guaranteed to initialize memory to anything, and the new-expression that allocates an unsigned int without a new-initializer leaves the object with an indeterminate value.

Reading the value of an uninitialized object results in undefined behavior. Undefined behavior includes evaluating to the value zero with no ill effects but could result in anything happening so you should avoid causing it.

In C++11, the language used is that the allocated objects are default-initialized which for non-class types means that no initialization is performed. This is different from the meaning of default-initialized in C++03.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
5

With some compilers, the debug version of new will initialise the data, but there is certainly nothing that you can rely on.

It is also possible that the memory just had 0 from a previous use. Don't assume that nothing happened to the memory between delete and new. There could be something done in the background that you never noticed. Also, the same pointer value might not be the same physical memory. Memory pages get moved and paged out and in. A pointer might be mapped to an entirely different location than earlier.

Bottom line: if you didn't specifically initialise a memory location then you can assume nothing about its contents. The memory manager might not even allocate a specific physical memory location until you use the memory.

Modern memory management is amazingly complex, but as a C++ programmer you don't really care (mostly‡). Play by the rules and you won't get into trouble.

‡ You might care if you are optimising to reduce page faults.

Michael J
  • 7,631
  • 2
  • 24
  • 30
3

That's not operator new, that's the new operator. There's actually a big difference! The difference is that operator new is a function that returns raw memory; when you use the new operator, it invokes a constructor for you. It's the constructor that's setting the value of that int, not operator new.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186