0

I am new to c++. From what I know, everytime I use "new", I need to delete the allocated memory using "delete". My problem is that I've written some code, but I can't figure out how to deallocate the memory in it.

I have these two functions:

double *Layer::calculateOutputs(const double *inputs) {
    auto *weightedInputs = new double[numCurrentLayerNodes];

    //function fills up the array here

    return weightedInputs;
}
double *NeuralNetwork::calculateOutputs(double *inputs) {
    for (auto &layer: layers) {
        double *layerOutput = layer.calculateOutputs(inputs);
        delete[] inputs;
        inputs = layerOutput;
    }

    return inputs;
}

The way it is right now I get a heap corruption error, but I don't really understand why. If I don't delete inputs and I change the function to something like this:

double *NeuralNetwork::calculateOutputs(double *inputs) {
    for (auto &layer: layers) {
        inputs = layer.calculateOutputs(inputs);
    }

    return inputs;
}

The error disappears, but I'm pretty sure that even though I changed what array "inputs" points to, those arrays are still somewhere in memory, so where exactly am I supposed to delete it?

I know I could save myself a lot of pain by just using vectors, but this isn't my first programming language, so I kind of want to challenge myself and try to manage memory and stuff, since that is what I find interesting about c++ in the first place.

Paul
  • 19
  • 5
  • 1
    Maybe your real problem is this: [https://stackoverflow.com/questions/11024438/rule-of-three-in-c](https://stackoverflow.com/questions/11024438/rule-of-three-in-c) – drescherjm Jun 06 '23 at 14:29
  • 5
    Consider not using `new` at all. You can achieve the same functionality with a combination of `std::unique_ptr` and `std::array`/`std::vector`. – Jakob Stark Jun 06 '23 at 14:30
  • 5
    If `numCurrentLayerNodes` is a runtime variable then replace `auto *weightedInputs = new double[numCurrentLayerNodes];` with `std::vector`. If it is a compile time constant replace with `std::array`. In current C++ the use of new/delete should be very limited (only inside some datastructures) – Pepijn Kramer Jun 06 '23 at 14:32
  • 2
    It is certainly important to understand how to use dynamic memory management in C++, and the proper techniques for doing so. However, this is often poorly taught, and results in a fairly common rabbit-hole called "Pointless Use Of Pointers". Pretty much all of the shown code can be rewritten using `std::vector` and letting the C++ library handle the task of correctly managing dynamic memory handling. – Sam Varshavchik Jun 06 '23 at 14:32
  • @JakobStark, but if I don't use new my IDE complains that I am returning a pointer that points to a memory address on the stack. Is that ok? – Paul Jun 06 '23 at 14:33
  • 1
    @Paul No, that's not okay. It suggests that you did not actually use `std::vector`. – Nathan Pierson Jun 06 '23 at 14:34
  • @SamVarshavchik Indeed regrettably it seems like most teaching material is stuck pre 1998 (std::vector was already introduced in C++98). – Pepijn Kramer Jun 06 '23 at 14:34
  • @Paul Return a `std::vector` not a `double*` and you will be fine. C++ make sure no unecessary copies of the data are made in this case – Pepijn Kramer Jun 06 '23 at 14:35
  • One misunderstanding: "Even though I changed what array `"inputs"` points to..." No, you didn't. `inputs` is a `double*` that was passed by value. You changed what the local copy points to. – Nathan Pierson Jun 06 '23 at 14:35
  • @Paul do you know about the cpp reference website? It has more documentation for you on [std::vector](https://en.cppreference.com/w/cpp/container/vector) and a lot of other things too – Pepijn Kramer Jun 06 '23 at 14:38
  • 1
    @PepijnKramer yes, I was shocked to find out that even today the idea is still "C is simple, C++ is complex, first learn C, then the C++ that looks like C and then the 'difficult' part of C++" while students can be productive quickly with std::vector and std::string but they don't want to teach that because namespaces and templates are only chapter 25 and 36... – stefaanv Jun 06 '23 at 14:38
  • 1
    If you are learning C++ then selecting neural network for this is a bad choice. If you like to learn how to use neural networks then use of C++ is bad choice. Python and tensor flow will allow you to do this quickly and calculation will be done on graphics card which will be literally 100 times faster. If you learning C++ then select some simpler problem to write your first ... tenth code. – Marek R Jun 06 '23 at 14:39
  • 1
    @stefaanv -- The ironic thing is that a total beginner to programming sees `std::vector` as simpler than `new[]` and `delete[]`. I think the programmer with experience already in `C` has that bias, where when they see syntax like `std::vector`, automatically it looks more difficult. – PaulMcKenzie Jun 06 '23 at 14:43
  • 1
    @stefaanv Yes C++ is actually less complex then C at least it is harder to make buggy code. the actual language is more rich. But I think the main reason is that "C" style "C++" is used because teachers teach about datastructures (and think lowest level access is needed for that) but they still want the "classes" part of C++. End result a nasty unmaintainable mix of the two languages. – Pepijn Kramer Jun 06 '23 at 14:49
  • Looked more carefully at your code -- yes, it should work, and the culprit is most probably the caller of NeuralNetwork::calculateOutputs -- what do you pass it? Is it allocated with new double[size]? – Mike Tyukanov Jun 06 '23 at 17:52
  • This doesn’t address the question, but the true rule is that if you use `new` you must also use `delete`, and if you use `new []` (as the code in the question does) you must use `delete []`. – Pete Becker Jun 06 '23 at 19:06
  • @PeteBecker, yes, and in this code new[]/delete[] match well. What we don't see is how the first pointer was obtained, and how it was disposed in the end. Judging from the fact that the removal of delete[] inside the cycle solves memory error, the primary suspect is the first allocation (and possibly some pointer manipulations prior to NeuralNetwork::calculateOutputs call). Another missing thing is the actual error as well as the compiler and debugger version. Usually in debugger such crashes give more meaningful messages, e.g., "object (addr): pointer being freed was not allocated" (gdb) – Mike Tyukanov Jun 06 '23 at 19:41

1 Answers1

0

Memory management is a complex operation inherited from C language. The rule is that you can only call delete[] on something that was obtained with new[], but you should call delete[] on everything that was obtained with new[].

A common problem for beginners is when the initial array is not a dynamic one:

  • you are not allowed to delete[] it
  • but you shall delete[] every following array

A possible workaround is to initialy allocate an array and copy the initial values in it. But the correct and idiomatic way is to only rely on standard containers (here std::vector) and never user raw dynamic arrays. In fact, new[] and delete[] should be seen as low level primitives and should only used to implement special containers.

Long story made short:

  • either you are using C language and have to carefully manage memory allocation
  • or you are using C++ language and should only use standard containers
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252