Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What type of object should this function return?

Consider this class:

class Widget
{
    Widget::Widget();
    bool initialize();
}

A Widget has the following characteristics:

  1. initialize() must be invoked to fully construct
  2. initialize() may fail
  3. initialize() is expensive

Given that, I am encapsulating creation in factory function that always returns the same Widget instance:

Widget* widget() {
    static auto w = new Widget;
    static auto initialized = false;

    if (!initialized) {
        if (!w->initialize()) {
            return nullptr;
        }
        initialized = true;
    }

    return w;
}

What should the return type of widget() be?

In particular, I'd like to somehow make it clear that the lifetime of the returned Widget will outlast any caller, but without referencing the internal implementation.

  1. Return a raw pointer and add a comment that states "The returned pointer points to an object with static storage duration that will not be deleted before the end of the program". This is simple, but not self-documenting.
  2. Return a std::shared_ptr<Widget>. This is self-documenting, but I don't like that it will introduce completely unnecessary reference counting overhead.
  3. Return a std::unique_ptr<Widget> with a custom deleter function that is a no-op. I think this has the same perceived problem as #2 if the caller converts it into a shared_ptr.
like image 884
Josh Avatar asked Jan 25 '15 23:01

Josh


2 Answers

I vote for:

boost::optional<Widget&> widget() {
    static Widget w; // no reason for this to be a pointer
    static bool initialized = false;

    if (!initialized) {
        if (!w.initialize()) {
            return boost::none;
        }
        initialized = true;
    }

    return w;
}

It makes it clear that the caller doesn't own the Widget in any way, there's no worry of the caller delete-ing the Widget, and it's clear whether or not the call succeeded.

like image 103
Barry Avatar answered Nov 13 '22 10:11

Barry


Isn't a raw pointer the right thing to do here? It expresses the restrictions already. It can fail (by returning nullptr), and since it makes no promises about the pointer, callers can't safely cause it to be deleted. You're getting a raw pointer, you can't make the assumption that you're allowed to make any statements about the lifetime of the pointed-to object.

like image 7
Andre Kostur Avatar answered Nov 13 '22 09:11

Andre Kostur