问题
I'm writing a simple container class in C++ similar to a map that stores objects indexed by a key. I'd like to provide an accessor function such as:
V& getValue(const K &key);
where I return a reference to the value.
But I also wanted to handle the case where the key/value is not present and be able to return some status to the user (there could be some reasons why it is not there that I want to communicate back to the caller via some Status type).
I suppose I could do the following but calling this would require a V object to be constructed before this function can be called, and I'm just going to copy the internal V object into the one being passed in by reference, so that seems bad.
Status getValue(const K &key, V& v);
I could also do:
V &getValue(const K &key, Status &s);
But for some reason that seems a little bit clunky as focus is drawn away from the Status and users may forget to check it (but maybe that's not my problem).
So is there anyway to have a function similar to
Status getValue(const K &key, V& v);
without the a dummy V object needing to be constructed before calling it? You can't pass a reference to a reference. I suppose I could use pointers and am happy to do so, but it is less desirable for creating a simple to use and reason about function.
Any thoughts?
回答1:
The usual solution is to provide a bool contains(const K &key)
function and if you don't want your accessor to silently create entries, have it throw an exception instead. (having two accessors, one that throws an exception, and another that creates entries is also common)
Of course, this may not be what you want. What is the reason you want to fit all this into a single function?
回答2:
You could go with your original function V& getValue(const K &key)
, and throw an exception to indicate non-successful Status
values.
Then, callers have the option of delaying how they handle the problem (by letting the exception bubble up to an appropriate handler), but they cannot outright forget about it because the program will crash otherwise. The call site needn't be cluttered with status-checking and error-reporting code.
回答3:
I would go with boost::optional
or create a similar template if you don't want to use boost. With boost::optional
your function will look like this:
boost::optional<MyClass &> getValue(const K &key)
回答4:
I see 3 options:
- Return a "wrapper" object that can be converted to V& and can tell whether it stores a valid reference or not (can be implemented around V*).
- Return a pointer.
- Return a reference and throw and exception if the key is not found.
I personally would go with a pointer.
回答5:
Consider returning boost::variant<V &, Status>
or (equivalently) boost::variant<std::reference_wrapper<V>, Status>
.
回答6:
I would follow an idea from std::map interface:
std::pair<iterator,bool> getValue(const K& key);
The value object is accessible through the iterator, the bool
flag shows if the value was present.
回答7:
First I'll answer your question as written: I would suggest returning a boost::optional<boost::ref<V> >
so that you can still return by reference, but optionally so.
However, I wouldn't suggest this interface. The standard containers already have an interface that solves this exactly problem, namely returning iterators rather than values. I would suggest just using an "iterator" interface (it doesn't have to be a real full-blown iterator) and returning an end
/one past the end to indicate that the iter is not found, rather than returning by reference or not. The more you make your container's interface look like a standard container, the greater your options for using standard algorithms AND plugging it in anywhere you want as a substitution.
来源:https://stackoverflow.com/questions/11970974/what-function-signature-should-i-use-to-return-a-reference-to-an-object-that-mig