C++ get method - returning by value or by referenc

2020-06-18 00:56发布

问题:

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.

#Q

What would be your choice in this kind of situation and why?

回答1:

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:

  • Passing by value in 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."
  • Using a 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:

  • Returning by copy seems a waste since most times you won't modify the object returned (for a settings map), however pointer or reference do mean that the object aliased will live long enough, if you can't guarantee it then the point is moot: return by value. Also copy allow to avoid exposing an internal detail, for example if you were suddenly to switch to std::wstring because you need some settings in UTF-8...
  • If you need performance, then you are ready to do some concessions in this department. However a reference does not allow you to signal the absence of the property (unless you have some magic value) while the pointer makes it easy (NULL is already cut out for you).


回答2:

That depends on the usage. Should GetValue("foo") = "bar" make sense? In that case, return by value does not do what you want.



回答3:

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.



回答4:

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.