C++ get 方法 - 按值或按引用返回

发布于 2024-09-03 11:36:15 字数 520 浏览 4 评论 0原文

我问了一个非常简单的问题,但不幸的是我自己无法找到答案。

假设我有一些数据结构来保存设置并充当设置映射。 我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

你的心境我的脸 2024-09-10 11:36:15

实际上我可能会

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:

  • SetValue 中按值传递允许编译器进行一些无法通过 const 引用传递进行的优化,Dave Abrahams 在一篇文章中对此进行了解释,“想要速度?按值传递。”
  • 使用Setter 通常更好,因为您可以检查正在设置的值,而使用普通引用则不能保证调用者不会对数据做任何愚蠢的事情。

对于 getter:

  • 通过复制返回似乎是一种浪费,因为大多数时候您不会修改返回的对象(对于设置映射),但是指针或引用确实意味着别名的对象将生存足够长的时间,如果您不能保证它那么这一点就毫无意义了:按值返回。还可以复制允许避免暴露内部细节,例如,如果您突然切换到 std::wstring 因为您需要 UTF-8 中的一些设置...
  • 如果您需要性能,那么您就是准备在这个部门做一些让步。然而,引用不允许您表示属性不存在(除非您有一些神奇的值),而指针则可以轻松实现(NULL 已经为您删除)。

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).
掀纱窥君容 2024-09-10 11:36:15

这取决于用途。 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.

眼前雾蒙蒙 2024-09-10 11:36:15

如果您可以通过 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.

满天都是小星星 2024-09-10 11:36:15

这是C++非常“敏感”的一点。恕我直言,这是 C++ 设计的最弱点之一。
AFAIK 没有真正好的选择,既美观又性能良好。

值得一提的是,RVO 优化通常只完成一部分工作。如果没有它,典型的表达是这样的:

std::string txt = GetValue("...");

实际上会产生 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:

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.

寂寞笑我太脆弱 2024-09-10 11:36:15

我添加这个答案是为了避免未来对 C++ 经验较少的读者编写产生未定义行为的代码。

该问题没有指定 Getter 函数所属的类是否存储要返回的值的副本。

让我们首先处理按值返回的情况。这是您通常会选择的选项。

std::string GetValue(const std::string& name) const

这是有效的 C++,不会产生未定义的行为。

OP 没有指定返回值是如何产生的。可能是这样的:

std::string GetValue(const std::string& name) const
{
    std::string temporary = function_of_name(name);
    // for example:
    // std::string temporary = "Hello " + name + "!";
    return temporary;
}

在上面的示例中,在 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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文