4

I have read here, as well as elsewhere, that deleting the same variable twice can be disastrous (even when there is more than one variable name).

Suppose I have a function which takes an input and output array:

void test(int*& input, int*& output) {
  if(input[0] == 0) {
    output = input;
  }
}

and it may assign a pointer to another variable I'm using:

int *input = new int[3];
int *output = new int[3];

input[0] = 0;

test(input, output);

delete[] input;
delete[] output;

how can I avoid the double delete?

In this overly simplified scenario, I know I could check the pointer addresses to see if they are equal and conditionally only delete one of them, but is there a better solution when I won't know pointers might be pointing to the same memory?

Edit:

tidied up the things to avoid some confusion..

Community
  • 1
  • 1
snapfractalpop
  • 1,798
  • 2
  • 19
  • 27
  • 5
    *"how can I avoid the double delete?"* This isn't snarky, so don't read it as such - [don't use `new`](http://stackoverflow.com/questions/6500313/). – Drew Dormann Aug 16 '15 at 03:03
  • 1
    And don't use `delete` either – M.M Aug 16 '15 at 03:05
  • 1
    Your code does not have a double delete anyway, `input` and `output` point to different buffers. The local variables of the same names inside `test` do not affect variables outside the function. – M.M Aug 16 '15 at 03:06
  • @DrewDormann in that answer, it describes using the stack instead of the heap. I was using ```new``` for passing a blank array to an initializer list for a struct (inline). Is there a way to get a new stack-based array with the initializer list syntax? Or should I just declare a variable? – snapfractalpop Aug 16 '15 at 03:16
  • "passing a blank array to an initializer list for a struct (inline)" - huh? It would help to post the code you are trying to describe. – M.M Aug 16 '15 at 03:23
  • Did you mean to make the parameters to `test` be `(int*& input, int*& output)`? As RSahu pointed out, your code does not suffer from a "double delete". The double delete requires pointers passed by reference or pointers to pointers. – Derek Aug 16 '15 at 03:31
  • @MattMcNabb I didn't want to confuse the issue too much, but a struct like ```foo {int *array; int someVar}``` and function takes a foo as ```test({new int[5], 42});``` – snapfractalpop Aug 16 '15 at 03:31
  • @Derek no, I was trying to keep it simple, but in the real code, the references are to structs, so the local shadowing is not an issue. I feel I've muddied the waters... but I'm learning a lot! – snapfractalpop Aug 16 '15 at 03:33
  • @snapfractalpop that would be an extremely bad struct design – M.M Aug 16 '15 at 03:35
  • @MattMcNabb bad because it has a variable size array with no size variable? – snapfractalpop Aug 16 '15 at 03:39
  • @snapfractalpop because it is unclear who manages the memory for `array`. (which is a ponter, not an array). Anything with raw pointers, new, or delete is suspect. – M.M Aug 16 '15 at 03:40
  • @MattMcNabb any advice on where to read up more? – snapfractalpop Aug 16 '15 at 03:43
  • `output = input;` does not do what you think it does. – user253751 Aug 16 '15 at 04:14
  • @immibis in theory, this means that every time I think it does something, it has to do something else. I can't imagine everything that it can do, but I can imagine imagining everything it can do. So, then I think it must do nothing, forcing it to do something, and restarting the loop. Surely it does one thing: confuses the whole thread. One stroke of carelessness in the name of simplicity.. and brain == fried. – snapfractalpop Aug 16 '15 at 04:37
  • @snapfractalpop It doesn't do what you thought it did when you wrote it – user253751 Aug 16 '15 at 04:43
  • @immibis I knew that when I wrote it.. and was careless anyway because I didn't consider it important for the underlying question. In reality, the code has a function that takes structs, and only part of the referenced output struct is reassigned to the input part. Basically, to avoid confusion, I caused more confusion. I hope it's clear enough now with this comment, and the one replying to Derek. – snapfractalpop Aug 16 '15 at 04:49

2 Answers2

7

The way to avoid double deletes is to design your code so that the ownership of objects is well defined. There can only be one owner of an object at a time, though ownership can be passed from one owning entity to another. An object owner can be a piece of code (such as a function) or a data structure. When the owner is done with an object, it is the owner's responsibility to either pass ownership to something else or to destroy the object.

Michael Burr
  • 311,791
  • 49
  • 497
  • 724
6

Generally speaking the best way to avoid double delete is to not allocate memory directly with new. There are various smart pointers you can use like scoped_ptr and shared_ptr, and in your case you can use std::Vector:

typedef std::vector<int> Ints;

void test(const Ints& input, Ints& output)
{
  if(input[0] == 0) {
    output = input;
  }
}

Ints input(3);
Ints output(3);

input[0] = 0;

test(input, output);
Mark B
  • 91,641
  • 10
  • 102
  • 179