C++ get 方法 - 按值或按引用返回
我问了一个非常简单的问题,但不幸的是我自己无法找到答案。
假设我有一些数据结构来保存设置并充当设置映射。 我有一个 GetValue(const std::string& name) 方法,它返回相应的值。
现在我想弄清楚 - 什么样的返回值方法会更好。最明显的方法是让我的方法表现得像
std::string GetValue(const std::string& name) const
并返回对象的副本,并在性能方面依赖 RVO。
另一种方法意味着创建两种方法
std::string& GetValue(...)
const std::string& GetValue(...) const
,这通常意味着复制代码或使用一些邪恶的常量转换来两次使用这些例程之一。
#
问
在这种情况下您会选择什么?为什么?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
实际上我可能会
首先使用:Setter:
SetValue
中按值传递允许编译器进行一些无法通过 const 引用传递进行的优化,Dave Abrahams 在一篇文章中对此进行了解释,“想要速度?按值传递。”对于 getter:
std::wstring
因为您需要 UTF-8 中的一些设置...Actually I would probably use:
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...这取决于用途。
GetValue("foo") = "bar"
应该有意义吗?在这种情况下,按值返回不会达到您想要的效果。That depends on the usage. Should
GetValue("foo") = "bar"
make sense? In that case, return by value does not do what you want.如果您可以通过 const 引用返回,请执行此操作。按值返回 std::string 等内存管理类的唯一原因是因为它是临时字符串。
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.
这是C++非常“敏感”的一点。恕我直言,这是 C++ 设计的最弱点之一。
AFAIK 没有真正好的选择,既美观又性能良好。
值得一提的是,RVO 优化通常只完成一部分工作。如果没有它,典型的表达是这样的:
实际上会产生 2 个副本!
取决于编译器,但通常 RVO 优化仅消除一个副本,但另一个副本仍然存在。
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:
will actually produce 2 copies!
Depends on the compiler, but usually RVO optimization eliminates just one copy, however the other is still there.
我添加这个答案是为了避免未来对 C++ 经验较少的读者编写产生未定义行为的代码。
该问题没有指定 Getter 函数所属的类是否存储要返回的值的副本。
让我们首先处理按值返回的情况。这是您通常会选择的选项。
这是有效的 C++,不会产生未定义的行为。
OP 没有指定返回值是如何产生的。可能是这样的:
在上面的示例中,在
GetValue
范围内创建了一个临时对象。在函数作用域的末尾,它按值返回,这意味着要么创建对象的副本,要么更有可能编译器执行返回值优化 (RVO)(C++ 11 之前和之后)并且该副本是“优化的”出”或“省略”。请不要将此与现代 C++ 11 及更高版本的“移动语义”混淆。这是一个不同但相关的概念。 RVO 在移动语义之前就已经存在,并且大多数优秀的 C++ 03 编译器都将执行 RVO。
要点是,在这里返回任何类型的引用(例如 std::string& )都会产生未定义的行为,因为该对象在函数体末尾超出了范围,并且返回的引用现在指向已从记忆中删除/删除的东西。 (引用只是应用了额外语法糖的指针。)
第二种情况
如果类存储要返回的对象的副本,则返回引用是有效的操作。然而,它不可能比第一个 RVO 案例快很多。
如果有必要,我可以稍后对此进行扩展以添加更多详细信息,但希望现在已经清楚为什么会出现这种情况。
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.
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:
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.