gpt4 book ai didi

c++ - 为什么在 Herb Sutter 的 CppCon 2014 演讲中不推荐使用值(value) setter 成员函数(回到基础 : Modern C++ Style)?

转载 作者:IT老高 更新时间:2023-10-28 13:21:04 30 4
gpt4 key购买 nike

在 Herb Sutter 的 CppCon 2014 演讲中回归基础:现代 C++ 风格,他在幻灯片 28 (a web copy of the slides are here) 中提到了这种模式:

class employee {
std::string name_;
public:
void set_name(std::string name) noexcept { name_ = std::move(name); }
};

他说这是有问题的,因为当使用临时调用 set_name() 时,noexcept-ness 并不强(他使用短语“noexcept-ish”)。

现在,我在我自己最近的 C++ 代码中大量使用了上述模式,主要是因为它可以让我每次都输入两个 set_name() 拷贝 - 是的,我知道通过强制复制构造可能会有点低效每次,但嘿,我是一个懒惰的打字员。然而 Herb 的短语“This noexcept is problematic”让我担心,因为我在这里没有得到问题:std::string 的移动赋值运算符是 noexcept,它的析构函数也是,所以上面的 set_name() 似乎我保证没有异常(exception)。我确实看到编译器 before set_name() 在准备参数时抛出了一个潜在的异常,但我很难将其视为有问题的。

稍后在幻灯片 32 Herb 上明确指出上述是反模式。有人可以向我解释一下,为什么我一直因为懒惰而写出糟糕的代码?

最佳答案

其他人已经涵盖了上面的 noexcept 推理。

Herb 在效率方面的讨论上花费了更多时间。问题不在于分配,而在于不必要的解除分配。当您将一个 std::string 复制到另一个时,如果有足够的空间来保存正在复制的数据,则复制例程将重用分配的目标字符串存储空间。在进行移动分配时,必须释放目标字符串的现有存储空间,因为它会从源字符串中接管存储空间。 “复制和移动”习语强制释放总是发生,即使你没有传递一个临时的。这是稍后在演讲中展示的可怕表现的根源。他的建议是改为使用 const ref,如果您确定需要它,则对 r 值引用进行重载。这将为您提供两全其美的优势:为非临时人员复制到现有存储中,避免解除分配,并为临时人员以一种或另一种方式支付解除分配费用(目的地在移动之前解除分配或复制后源释放)。

以上不适用于构造函数,因为成员变量中没有存储空间可以释放。这很好,因为构造函数通常需要多个参数,如果您需要为每个参数执行 const ref/r-value ref 重载,最终会导致构造函数重载的组合爆炸。

现在的问题变成了:有多少类在复制时重用像 std::string 这样的存储?我猜 std::vector 确实如此,但除此之外我不确定。我确实知道我从来没有写过像这样重用存储的类,但是我写了很多包含字符串和 vector 的类。对于不重用存储的类,遵循 Herb 的建议不会对您造成伤害,首先您将使用 sink 函数的复制版本进行复制,如果您确定复制对性能的影响太大,那么您将进行 r 值引用重载以避免复制(就像您对 std::string 所做的那样)。另一方面,使用“复制和移动”确实对 std::string 和其他重用存储的类型有性能影响,并且这些类型可能在大多数人的代码中得到很多使用。我目前正在听从 Herb 的建议,但在我认为问题完全解决之前需要再考虑一下(可能有一篇博文我没有时间写潜伏在这一切中)。

关于c++ - 为什么在 Herb Sutter 的 CppCon 2014 演讲中不推荐使用值(value) setter 成员函数(回到基础 : Modern C++ Style)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26261007/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com