Search code examples
c++pointersnew-operator

Uninitialized memory warning on structs instantiated with new


So I have a Node struct

struct Node
{
    int x = 0;
};

I make 20 Node*s. My understanding is that Node** is a pointer to the start of an array that holds pointers to Nodes.

constexpr int mazeSize = 20;
Node** testMaze = new Node * [mazeSize];

After this, I started getting warnings and errors when I tried to do anything with it. Examples:

testMaze[0]->position.x == 0; //->Using uninitialized memory `*testMaze` and 

What I understood from this error: *testMaze is dereferencing the array of pointers, which means it's referring to the first Node object in that array. If this is the case than how would I initialize it? If I simply created the Node* as so:

Node* node = new Node;
node->x = 0; 

Than it works fine and there is no need to initialize it, so why not with the way I am doing it? I also don't understand how to initialize a struct.

Another examlpe:

testMaze[0]->x == testMaze[1]->x //->Runtime error: Access violation reading error
testMaze[0]->x = 0; //->Runtime error: Access violation writing error

How can I fix these problems? Thanks.


Solution

  • Always remember that pointer types are separate, concrete types with their own type and size. A pointer to T T* basically boils down to a small chunk of memory that is used to store an address to another memory area, which (hopefully) contains an instance of some type T.

    With

    Node** testMaze = new Node * [mazeSize];

    you are allocating an array of maxSize pointer sized elements of type Node* and sizeof(Node*) (which on modern platforms is usually 4 or 8 bytes, depending if your executable is meant to run in 32 bit or 64 bit mode).

    These newly created pointers are not initialized, and thus point to invalid addresses, unless you also zero initialize the array:

    Node** testMaze = new Node * [mazeSize] {};
    assert (testMaze[0] == nullptr); // holds true
    

    In order to get an maxSize instances of Node, you have to, well, create maxSize instances of Node:

    Node** testMaze = new Node* [mazeSize];
    for (std::ptrdiff_t i {}; i < maxSize; ++i) {
        testMaze[i] = new Node { /* insert parameters here */ };
    }
    

    Given that you are using constexpr, I infer the revision of C++ you are targeting is C++11 or newer. In this case, you should be aware that operator new and operator new[] are almost always the wrong choice when writing modern C++, given that they only returns pointers whose ownership and lifetime you then have to manage by hand.

    You most definitely should start using STL containers, such as std::vector and std::array, which are easier to use and can avoid you a great deal of unnecessary pain. If you insist on using new, at least give a look to std::unique_ptr, which wraps a pointer or C array and automatically calls delete or delete[] as soon as it goes out of scope.