【发布时间】:2014-12-03 08:32:24
【问题描述】:
在 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() 似乎我保证没有例外。我确实看到编译器 before set_name() 在准备参数时抛出了一个潜在的异常,但我很难将其视为有问题的。
稍后在幻灯片 32 Herb 上明确指出上述是反模式。有人可以向我解释一下,为什么我一直因为懒惰而写出糟糕的代码?
【问题讨论】:
-
如果我没记错的话,Herb 说
noexcept在这里是一个神话,因为发生在被调用方一侧的分配可能会抛出(例如,从 原始字符串文字 或其他std::string)。所以body不会抛出,但是调用那个函数可能还是会抛出异常(std::bad_alloc) -
函数标记为
noexcept,但是调用它会抛出。在进入函数体本身之前抛出异常的事实开始进入“多少天使可以在针头上跳舞”的领域。 -
我基本同意你的观点,但我明白 Herb 的观点。
noexcept真的只是说“如果调用这个函数没有抛出,我保证你不会得到异常”,这可以说没有它可能有用。 -
IMO Herb 在那次演讲中所做的是从他在
std::string上运行的一些基准中获得一般性建议。这很愚蠢,使整个练习变得毫无意义。一般不要让const&超载。除了关于noexcept的事情之外,Herb 为一个孤独的const&辩护的论点对于std::string之外的其他任何事情都没有说服力。 -
@NiallDouglas:在幻灯片 23 的底部,他展示了“C++98:合理的默认建议”的表格,在幻灯片 24 的顶部,他展示了“现代 C++”的表格: 合理的默认建议”,两个表都是一样的。我不确定那里有什么不清楚的地方。