0

In the four method below, only better is what we should do. We want to dynamic allocation here to avoid a bad function return. But, where do we delete f? Delete at the function that calls better()? But there is no f any more in that case.

Foo *bad() {
  Foo f;
  return &f;
}

Foo &alsoBad() {
  Foo f;
  return f;
}

Foo mediocre() {
  Foo f;
  return f;
}

Foo * better() {
  Foo *f = new Foo;
  return f;
}
HoKy22
  • 4,057
  • 8
  • 33
  • 54
  • 1
    Put it into a smart pointer and return that to make the "better" one work better. – chris Mar 30 '13 at 00:44
  • 4
    `mediocre` is actually the best, just saying. See [_Modern C++ Style_](http://klmr.me/slides/modern-cpp/#1). Also see [_C++11 Style_](http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style) where Bjarne Stroustrup discusses move semantics. –  Mar 30 '13 at 00:44
  • 1
    You're basically asking "How do I do memory management", an incredibly broad and subjective topic. – Antimony Mar 30 '13 at 00:47
  • 2
    @Zoidberg is right. Even crustaceans know that manual resource management is crazy. – Blastfurnace Mar 30 '13 at 00:51

1 Answers1

5

But there is no f any more in that case.

Well, the pointer f goes out of scope, that's true, but we are still returning a pointer to the same object that f pointed to.

Therefore, we still have a handle to that object and we still can invoke delete on the returned pointer. In fact, you can invoke delete any time after creating an object with new.

What you have to take care is that:

  • you do indeed invoke delete at some point for each object allocated with new (otherwise you have a memory leak);
  • you do not call delete more than once for the same object, otherwise you get undefined behavior;
  • you do not dereference a pointer which points to an object that has been destroyed (i.e. a "dangling pointer"), otherwise you get undefined behavior.

In general, manual memory management through new and delete is discouraged in Modern C++, and ownership policies should be realized through smart pointers instead. OR...

In the four method below, only better is what we should do

Not exactly. In fact, I would say we should definitely not do better() - although we could do a version of better() modified to create and return a smart pointer rather than an owning raw pointer.

However, function mediocre() is actually pretty good, and that is for two reasons:

  1. First of all because it is very likely that the compiler will elide the call to the copy constructor and perform (Named) Return Value optimization, thus resulting in no run-time overhead;
  2. Secondly, because thanks to C++11's move semantics, it is possible to equip Foo with a move constructor that makes returning by value efficient in most cases even when no elision is performed.

Moreover, as Zoidberg correctly mentions in the comments, you should not use pointers at all if you do not really need them. Unique ownership can often by realized by creating objects with automatic storage duration (aka "on the stack"), and move semantics makes this practice efficient. Pointers should be created only when you need reference semantics.

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • 1
    I would add to the last sentence that in many cases ownership can be expressed without any pointers (or references, for that matter) at all. –  Mar 30 '13 at 00:48
  • @Zoidberg: Absolutely. Will mention that. Thank you – Andy Prowl Mar 30 '13 at 00:49
  • *you do indeed invoke `delete` at some point to all object allocated with `new`* I will admit this is sometimes not as easy to do as you would think, especially if you have different memory allocators. So the `better` function would have a complement, `betterCallMeWhenYouAreDone` that frees the allocated objects and you have to call it instead of `delete`. – ta.speot.is Mar 30 '13 at 00:52
  • @ta.speot.is: True, but I would rather think of forgetting of `better()` at all, because is actually `quite_bad()` in Modern C++. Manual memory management is superseded by smart pointers (which also support custom deleters), and those are saving us from most of the troubles you are probably thinking of in relation with the part of my answer you quoted. – Andy Prowl Mar 30 '13 at 01:02