Search code examples
c++smart-pointers

Is returning a reference to a managed memory a malpractice?


Given this code:

class Clazz {
 private:
  std::shared_ptr<int> something;

 public:
  Clazz() : something(std::make_shared<int>(0)) {}

  int &getSomething() {
    return *something;
  }
}

It leads to dangling references since the obtained reference might point at some moment to deallocated memory. For me it seems like a mirror of a dangling pointer scenario, but I failed to find any sources on that.


Solution

  • There is, again, a lot of "depends" and personal preferences with this kind of stuff.

    Lifetimes of "raw" pointers always need to be explicit.

    Things are easy if you have a smartpointer, and you give your internal functions raw pointers (or references) -- you just have to remember to not store these pointers anywhere. And since you're holding the smartpointer, all the functions you call with the raw pointer will have no issues.

    Things are slightly more complex when you return such pointers from an API. Even if it's my own API, I like to document it accordingly, such as

    /* ...
     * has<T> returns a pointer to the stored item, or nullptr.  This
     * pointer is valid until a yield.
     */
    

    to remind people and/or myself to not keep that pointer around.

    In other cases, I might return pointers to internal buffers, telling people that the data won't change until the next call is made.

    I'm not always writing down everything. As an example, if I return a pointer to an internal buffer, I don't generally mention that this pointer will become invalid when the object is destroyed. I'm generally assuming some level of expertise from users, and only document stuff that's not immediately obvious.

    Also note that raw pointers, in my book, have a validity -- but no free function associated with them. They just turn invalid at some defined point in time, but users never have to free them -- I'd always return something more advanced if such things need to be cleaned up.