4

In continuation to my previous question, I would like to ask the following :

Given a C++ function having a new statement in it but not returning anything explicitly (i.e. with a return statement), should it also always have a delete?

If no, could you please give me an example.

Community
  • 1
  • 1
tao
  • 51
  • 2

7 Answers7

4

The rule with new is very simple: the pointer returned by new must be deleted at some point by someone, somewhere in the code. If the pointer returned by new is lost, forgotten, or discarded, then you have a memory leak, and that is bad.

Therefore, if you new up some memory and return without storing it anywhere permanently, then you have leaked memory. Therefore, if you aren't going to delete it, then the pointer must be either stored in some kind of long-term storage (member of a class, static variable, etc) or it must be returned so that someone else can delete it.

Alternatively, you can just use a boost::shared_ptr and stop caring about (most of) this.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • `boost::shared_ptr` and similar are not *always* available (for example in C++ games very often), so these issues to still persist. – xan Jul 19 '11 at 10:17
  • @xan: `s/available/fast enough/` – Lightness Races in Orbit Jul 19 '11 at 10:21
  • Because often external libraries, such as boost, are not permitted into the code base. So if the library team haven't rolled their own... Obviously this depends on the team and what decisions have been taken with regards to available and in-house libraries and memory management policies. – xan Jul 19 '11 at 10:24
  • @xan: A lot of game developers are stuck in that "C with classes" mentality for C++ development. If that's how they want to develop, that's up to them. But that doesn't negate the advice. Nor does it mean that they _couldn't_ use it; they simply choose not to. – Nicol Bolas Jul 19 '11 at 10:31
  • @Nicol Bolas: Yes absolutely, was just giving an example of an area where it can still be relevant. Cheers. – xan Jul 19 '11 at 11:12
  • @xan, external libraries not allowed in a game code base?! Major games tend to use a large number of libraries. In particular they often use source libraries. Thus being "external" does not seem like it'd be a real reason to exclude boost from a game. – edA-qa mort-ora-y Jul 19 '11 at 12:06
  • @edA-qa mort-ora-y: On the games I've worked on, all "utility" libraries available were in-house implementations and no "external / pre-existing" libraries (like boost) were used. Thus `InHouse::List<>` etc. was the only list available, and `Boost::anything`, such as shared/smart pointers etc. were simply not available. Obviously this is not the case everywhere, but my understanding is that it is fairly common still for games companies to have in house utility libraries (which *may well* include memory management wrappers) as standard and not use external, public libraries for various reasons. – xan Jul 19 '11 at 13:33
4

It doesn't have to explicitly return the newly-created object, but it should pass it to something else in some way. Possible scenarios include:

  • In a member function, create an object and assign it to a field of the containing object.

Example:

class Foo {
    private:
        Baz* baz;
    public:
        Foo() : baz(0) { }
        void create_bar() { baz = new Baz(); }
        ~Foo() { delete baz; }
};
  • Passing the new object to something else.

Examples:

void foo() {
    // assuming bar lives in the global scope
    bar.baz = new Baz();
}

void foo2(Bar& bar) {
    bar.baz = new Baz();
    // or, better:
    bar.setBaz(new Baz());
}
  • Using some kind of garbage-collecting pointer type.

Example:

std::auto_ptr<Baz> foo() {
    return new Baz();
}
  • Passing the pointer into another function that does something with it and then deletes it.

Example:

void foo(Bar* bar) {
    bar->dostuff();
    delete bar;
}

void baz() {
    Bar* bar = new Bar();
    foo(bar);
}
tdammers
  • 20,353
  • 1
  • 39
  • 56
1

If the function creates a resource using new and doesn't pass a pointer to that resource back to anything then yes it must delete the resource otherwise it will never get cleaned up, causing a memory leak.

Chris Snowden
  • 4,982
  • 1
  • 25
  • 34
1

No, if the purpose of the function is to instantiate some data and hand it over to some other object. A (hypothetical) example from the games industry:

void AddProjectileAtPoint(int x, int y)
{
    Projectile *p = new Projectile(x, y);
    mProjectileManager->Add(p); //"mProjectileManager"'s job is to hold all projectiles and update them every frame...
}

In this case the purpose explicitly is to create a new object representing some data and store it somewhere for later use.

Obviously, there will need to be a matching delete at some point, but not within the function where the new occurs. This is fine as long as there is a clearly defined procedure for passing responsibility for managing the new'd memory to some other component.

In this case the structure is that the "Projectile Manager" takes responsibility for all projectiles it is given, will keep them alive for as long as is required and will clean-up the memory when it is appropriate.

xan
  • 7,440
  • 8
  • 43
  • 65
1

If you are allocating memory with new in a function, and that memory isn't accessible outside the function (or static), then it would need to be freed before the function exists. In this case, i'd recommend using std::auto_ptr or boost::scoped_ptr, as it will call delete for you when the function exits. Even if exceptions are thrown.

Node
  • 3,443
  • 16
  • 18
0

Not necessarily, if it's allocating a static object (e.g. to implement a Singleton pattern).

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
0

No, not necessarily. You might have stored a pointer to the dynamically-allocated object somewhere else. e.g. for some class A:

A* ptr = NULL;

void foo() {
   ptr = new A();
}

You should have a delete ptr somewhere, but it doesn't have to be in foo().

On the other hand, if you didn't store it anywhere else:

void foo() {
   A* ptr = new A();
}

Then, yes, this is a memory leak. You can never get back to that pointer to do delete ptr!


Note that it's better to use some "smart pointer" implementation like shared_ptr or unique_ptr to handle this stuff for you.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055