Reputation: 22854
I've go a very simple question, but unfortunately I can't figure the answer myself.
Suppose I've got some data structure that holds settings and acts like a settings map.
I have a GetValue(const std::string& name)
method, that returns the corresponding value.
Now I'm trying to figure out - what kind of return-value approach would be better. The obvious one means making my method act like
std::string GetValue(const std::string& name) const
and return a copy of the object and rely on RVO in performance meanings.
The other one would mean making two methods
std::string& GetValue(...)
const std::string& GetValue(...) const
which generally means duplicating code or using some evil constant casts to use one of these routines twice.
#
QWhat would be your choice in this kind of situation and why?
Upvotes: 7
Views: 12340
Reputation: 17266
I'm adding this answer to avoid future readers who are less experienced with C++ from writing code that produces undefined behaviour.
The question doesn't specify whether the class that the Getter function belong to stores a copy of the value to be returned.
Let us deal with the return by value case first. This is the option you would normally choose.
std::string GetValue(const std::string& name) const
This is valid C++ and does not produce undefined behaviour.
The OP didn't specify how the return value is produced. It might be something like this:
std::string GetValue(const std::string& name) const
{
std::string temporary = function_of_name(name);
// for example:
// std::string temporary = "Hello " + name + "!";
return temporary;
}
In the above example, a temporary object is created inside the scope of GetValue
. At the end of function scope it is returned, by value, which means that either a copy of the object is made, or more likely the compiler performs return value optimization (RVO) (pre and post C++ 11) and the copy is "optimized out" or "elided".
Please do not confuse this with modern C++ 11 and later "move semantics". This is a different but related concept. RVO existed before move semantics, and most good C++ 03 compilers will perform RVO.
The point being that returning any kind of reference here for example std::string&
produces undefined behaviour, because the object goes out of scope at the end of the function body and the returned reference is now pointing to something that has been deleted/removed from memory. (A reference is just a pointer with extra syntactic sugar applied.)
Second Case
If the class stores a copy of the object to be returned then returning a reference is a valid thing to do. However it is not likely to be much faster than the first RVO case.
I can expand on this to add more detail later if necessary, but hopefully it is now clear why this is the case.
Upvotes: 0
Reputation: 300209
Actually I would probably use:
std::string GetValue(const std::string& name) const;
// or
const std::string* GetValue(const std::string& name) const;
void SetValue(std::string name, std::string value);
Setter first:
SetValue
allows the compiler some optimizations that cannot be made with pass by const-reference, it's been explained in a article by Dave Abrahams, "Want Speed? Pass by Value."Setter
is usually better, because you can check the value being set whereas with a plain reference you have no guarantee that the caller won't do anything stupid with the data.For the getter:
std::wstring
because you need some settings in UTF-8...Upvotes: 6
Reputation: 12941
This is a very "sensitive" point of C++. IMHO it's one of the weakest points of C++ design. AFAIK there's no really good choice, which will be both look and perform good.
One point that should be mentioned that RVO optimization usually does only a part of the job. Without it a typical expression like this:
std::string txt = GetValue("...");
will actually produce 2 copies! Depends on the compiler, but usually RVO optimization eliminates just one copy, however the other is still there.
Upvotes: 1
Reputation: 146998
If you can return by const reference, do. The only reason to return a memory-managing class like std::string by value is because it's a temporary string.
Upvotes: 2
Reputation: 263320
That depends on the usage. Should GetValue("foo") = "bar"
make sense? In that case, return by value does not do what you want.
Upvotes: 6