How to delete a pointer after returning its value inside a function

25,291

Solution 1

Dynamic arrays are freed using delete[]:

char* block = ReadBlock(...);
// ... do stuff
delete[] block;

Ideally however you don't use manual memory management here:

std::vector<char> ReadBlock(std::fstream& stream, int size) {
    std::vector<char> memblock(size);
    stream.read(&memblock[0], size);
    return memblock;
}

Solution 2

Just delete[] the return value from this function when you've finished with it. It doesn't matter that you're deleting it from outside. Just don't delete it before you finish using it.

Solution 3

You can call:

char * block = ReadBlock(stream, size);
delete [] block;

But... that's a lot of heap allocation for no gain. Consider taking this approach

char *block = new char[size];
while (...) {
  stream.read(block, size);
}
delete [] block;

*Note, if size can be a compile time constant, you can just stack allocate block.

Solution 4

I had a similar question, and produced a simple program to demonstrate why calling delete [] outside a function will still deallocate the memory that was allocated within the function:

#include <iostream>
#include <vector>

using namespace std;

int *allocatememory()

{
    int *temppointer = new int[4]{0, 1, 2, 3};
    cout << "The location of the pointer temppointer is " << &temppointer << ". Locations pointed to by temppointer:\n";
    for (int x = 0; x < 4; x++)
        cout << &temppointer[x] << " holds the value " << temppointer[x] << ".\n";
    return temppointer;
}

int main()
{
    int *mainpointer = allocatememory();
    cout << "The location of the pointer mainpointer is " << &mainpointer << ". Locations pointed to by mainpointer:\n";
    for (int x = 0; x < 4; x++)
        cout << &mainpointer[x] << " holds the value " << mainpointer[x] << ".\n";

    delete[] mainpointer;
}

Here was the resulting readout from this program on my terminal:

The location of the pointer temppointer is 0x61fdd0. Locations pointed to by temppointer:

0xfb1f20 holds the value 0.

0xfb1f24 holds the value 1.

0xfb1f28 holds the value 2.

0xfb1f2c holds the value 3.

The location of the pointer mainpointer is 0x61fe10. Locations pointed to by mainpointer:

0xfb1f20 holds the value 0.

0xfb1f24 holds the value 1.

0xfb1f28 holds the value 2.

0xfb1f2c holds the value 3.

This readout demonstrates that although temppointer (created within the allocatememory function) and mainpointer have different values, they point to memory at the same location. This demonstrates why calling delete[] for mainpointer will also deallocate the memory that temppointer had pointed to, as that memory is in the same location.

Solution 5

Yes. You may call delete from outside of the function. In this case though, may I suggest using an std::string so you don't have to worry about the management yourself?

Share:
25,291
Emer
Author by

Emer

Updated on June 14, 2020

Comments

  • Emer
    Emer almost 4 years

    I have this function:

    char* ReadBlock(fstream& stream, int size)
    {
        char* memblock;
        memblock = new char[size];
        stream.read(memblock, size);
        return(memblock);
    }
    

    The function is called every time I have to read bytes from a file. I think it allocates new memory every time I use it but how can I free the memory once I have processed the data inside the array? Can I do it from outside the function? Processing data by allocating big blocks gives better performance than allocating and deleting small blocks of data?

    Thank you very much for your help!

  • Clark Gaebel
    Clark Gaebel almost 14 years
    Variable sized arrays aren't ISO C++, it's a GCC extension.
  • Clark Gaebel
    Clark Gaebel almost 14 years
    The definition of the function says that: char* ReadBlock(..., int size);
  • Stephen
    Stephen almost 14 years
    @wowus : This would obviate the need for the function, anyways, point taken... commented.
  • Georg Fritzsche
    Georg Fritzsche almost 14 years
    It has to be delete[], not delete.
  • Emer
    Emer almost 14 years
    Ok, but I cannot use strings because of read. istream& read ( char* s, streamsize n );
  • TOMKA
    TOMKA almost 14 years
    With this method, when the vector object is returned, does its copy constructor get called (I mean, do two instances exist at one point)?
  • Georg Fritzsche
    Georg Fritzsche almost 14 years
    @dream: It depends, most likely named return value optimization, NRVO, will kick in. See also the interesting Want Speed? Pass by value..
  • Emer
    Emer almost 14 years
    Wouldn't I run out of memory if I don't delete already read memory blocks?
  • Clark Gaebel
    Clark Gaebel almost 14 years
    Then use a vector instead. Sorry, didn't notice that.
  • Georg Fritzsche
    Georg Fritzsche almost 14 years
    Stephen, why has this become new int[size] instead of new char[size]?
  • Stephen
    Stephen almost 14 years
    @emerrf : You can reuse the same buffer, if your application allows for it (whether that's true isn't clear from your question). If it 's not possible to reuse the same buffer, then you should use a different approach - such as returning a string.
  • Stephen
    Stephen almost 14 years
    @Georg : Interesting post, but very misleading name. It almost sounds as if they're arguing pass-by-value instead of pass-by-reference. Link bait, I guess.
  • sigfpe
    sigfpe almost 14 years
    Ouch! The sad thing is that if you make this mistake, the compiler can't even detect it. What an awful language. Anyway, thanks. I'll fix the post. (Though it must be said, I wasn't actually proposing the entire line of code, just what builtin to use.)
  • 0xdky
    0xdky almost 14 years
    If it is not as trivial as the above example, I would always use BOOST shared_ptr (or intrusive_ptr if the type of data is a class). It may sound heavy weight but leads to consistent leak free code (almost).
  • Georg Fritzsche
    Georg Fritzsche almost 14 years
    @hack: Then shared_array<T> would be a better fit here, no need for a custom deleter.
  • TOMKA
    TOMKA almost 14 years
    @Georg: Ah I see! So, if I read correctly, the standard permits an optimisation that prevents a copy constructor from being called even if the copy ctor has side effects?
  • Georg Fritzsche
    Georg Fritzsche almost 14 years
    @dream: Yep, its a notable exception to the rule of not changing the observable behaviour. RVO is e.g. observable with logging-statements in both ctor and copy-ctor with X f() { return X(); } X x = f(); (activated optimizations assumed). If you have a standard handy see §12.8/15.