Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is memory allocated with new ever automatically freed?

I'm 99% certain the answer to this is a blinding no. Please validate my proposition that the following code will produce a memory leak.

Data &getData()
{
    Data *i = new Data();
    return *i;
}

void exampleFunc()
{
    Data d1 = getData();
    Data d2;

    /* d1 is not deallocated because it is on the heap, and d2 is
     * because it is on the stack. */
}

Please note that this is an oversimplified example, so clearly you wouldn't actually use the above code... So no need to point this out thanks.

Update 1:

To add to this, what if I assign the pointer to a reference? In this case, I assume that the data is not copied...

Data &getData()
{
    Data *i = new Data();
    return *i;
}

void exampleFunc()
{
    // Does copying occur here?
    Data &d1 = getData();

    // Does this deallocate the memory assigned to the pointer?
    delete &d;
}

Update 2:

I guess to answer my own question (in update 1) the following code proves that assigning a reference to a reference does not cause a copy...

#include <iostream>
#include <string>

using namespace std;

class Data
{
public:
    string mName;

    Data(const string &name) : mName(name)
    { cout << mName << " default ctor" << endl; }

    Data(const Data& other)
    {
        mName = other.mName + " (copy)";
        cout << mName << " copy ctor" << endl;
    }

    ~Data()
    { cout << mName << " dtor" << endl; }

    static Data &getData(const string &name)
    {
        Data *d = new Data(name);
        return *d;
    }
};

int main()
{
    cout << "d1..." << endl;
    Data d1 = Data::getData("d1");

    cout << "d2..." << endl;
    Data d2("d2");

    cout << "d3..." << endl;
    Data &d3 = Data::getData("d3");

    cout << "return..."  << endl;
    return 0;
}

Yields the following result...

d1...
d1 default ctor
d1 (copy) copy ctor
d2...
d2 default ctor
d3...
d3 default ctor
return...
d2 dtor
d1 (copy) dtor

Thanks to Eric Melski for a great answer (my code in update 2 is a modified copy of his exmaple code).

like image 356
Nick Bolton Avatar asked Apr 19 '09 19:04

Nick Bolton


2 Answers

Actually both d1 and d2 will be deallocated, because they are both on the stack. What is not deallocated is the Data object you allocated in your getData() function. You can see this a little more clearly if you flesh out your Data class with instrumentation in the constructors and destructor. For example:

class Data {
public:
    Data() { cout << "Data default ctor" << endl; }
    Data(const Data& other) { cout << "Data copy ctor" << endl; }
    ~Data() { cout << "Data dtor" << endl; }

    static Data& getData()
    {
        Data *i = new Data();
        return *i;
    }
};

Note that I have explicitly declared the copy constructor for Data. In your example you are implicitly calling that constructor when you do Data d1 = getData();, and I suspect this is where your confusion is coming from. Now if I run this simple program:

#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    Data d1 = Data::getData();
    Data d2;

    return 0;
}

The output is as follows:

Data default ctor
Data copy ctor
Data default ctor
Data dtor
Data dtor

Line-by-line, here's what you're seeing:

  1. The default constructor is invoked when you allocate a new Data in getData().
  2. The copy constructor is invoked to create d1 from the dynamically allocated Data you just made.
  3. The default constructor is invoked to create d2.
  4. The destructor is invoked for d2 when it goes out of scope at the end of main().
  5. The destructor is invoked for d1 when it goes out of scope at the end of main().

Note that there are three constructor calls, but only two destructor calls -- indicating that you have leaked exactly one Data object.

Hope that helps,

Eric Melski

like image 95
Eric Melski Avatar answered Oct 04 '22 20:10

Eric Melski


d1 is a stack object, copy-constructed from the reference returned from getData(). d1 is freed, but the object created in getData() is leaked.

like image 38
Chris Jester-Young Avatar answered Oct 04 '22 21:10

Chris Jester-Young