C.83: What's the rationale behind the C++ core guidelines recommending defining your own swap function anytime you have a value-like type?

huangapple go评论70阅读模式
英文:

C.83: What's the rationale behind the C++ core guidelines recommending defining your own swap function anytime you have a value-like type?

问题

I'll provide a translation for the text you've shared:

参考此链接

我正在尝试理解何时为我的类创建自定义的 swap() 函数。之前的研究表明,自从 C++11 以来,std::swap() 函数已经使用了移动语法,如果你想在你的类上调用 swap,通常最好只使用标准版本,因为移动语义通常是交换即使具有深层资源的类的最有效解决方案。我看到有人建议只有在你有一个无法与标准版本一起使用的奇怪类时才使用自定义 swap 函数,比如一个不能移动但你希望能够交换的类。

在这种情况下,为什么 C++ 核心准则建议每当你有一个非平凡可复制的类时都要定义自己的 swap 函数呢?如果有一点我认为更有效的是,只有在你没有移动构造函数(但仍然希望能够交换它)时才记得定义一个。

我参考了像这样的讨论,这些讨论得出的结论是,由于移动语义,现在创建自定义 swap 更像是一种特例。Std::swap() 不再使用复制语义,这使得在 C.83 中关于是否要创建 swap 函数的建议基于它是否可复制,而不是可移动。

请注意,我只提供翻译而不提供进一步的解释或回答。

英文:

Referring to this

I'm trying to understand when to create a custom swap() function for my classes. Researching it previously, it looks like ever since c++11 the std::swap() function has used move syntax and that if you want to call swap on your class, it's often best to just use the std version since move symantics are often the most effective solution to swapping even classes with deep resources. I've seen it recommended to only use custom swap functions if you have a bizarre class that won't work with the std version, such as a class that isn't movable but you do want to be swappable.

In that case, why do the c++ core guidelines recommend defining your own anytime you have a non trivially copyable class? If anything I figure it'd be more effective to remember to define one anytime you don't have a move constructor (but still want to be able to swap it).

I'm referencing discussions like this, which come to the conclusion that creating a custom swap now feels more like a special case, thanks to move semantics. Std::swap() no longer uses copy semantics, which makes it feel odd that in C.83 the recommendation for whether or not to make one is based off of whether or not it's trivially copyable, not movable.

答案1

得分: 3

  • 指南建议“考虑”提供一个交换操作,这比建议一个更弱。

  • 明确提供 noexcept 成员交换操作有助于记录交换操作是否确实是 noexcept

  • 执法部分指出,一个非平凡可复制类“应该”有一个交换操作。如果它不是平凡可复制的,那么您必须提供复制构造函数和复制赋值运算符,这将抑制移动构造函数和移动赋值运算符的自动生成。如果您忘记明确添加这些,那么 std::swap 将悄然退化为三次复制,而不一定是 noexcept

  • 正如指南所指出的,一个常见的模式是根据交换操作和复制构造函数来实现复制赋值。明确提供一个交换操作确保此模式按预期工作。

  • 如果对象很大,因为它有许多成员,那么 std::swap 会在堆栈上放置一个大的临时对象。您自己的交换方法只需要足够的堆栈来临时存储最大的单个数据成员。

  • 如果对象的某个数据成员未提供执行 noexcept 交换操作的方法(无论是明确提供还是确保具有 noexcept 移动语义),那么您将增加尽早发现这一问题的机会。

英文:
  • The guideline says to "consider" providing a swap, which is a bit weaker than recommending one.

  • Explicitly providing a noexcept member swap helps document whether a swap will indeed be noexcept.

  • The enforcement section says a non-trivially copyable class "should" have a swap. If it's not trivially copyable, then you had to provide a copy constructor and copy assignment operator, which will suppress the automatic generation of the move constructor and move assignment operator. If you forgot to add those explicitly, then std::swap will quietly fall back to three copies and won't (necessarily) be noexcept.

  • As the guideline notes, a common pattern is to implement copy assignment in terms of swap and a copy constructor. Having an explicit swap ensures this pattern works as intended.

  • If the object is large because it has many members, then the std::swap is going to put a large temporary on the stack. Your own swap method will only need enough stack to temporarily store the largest single data member.

  • If one of the object's data members failed to provide a way to do a noexcept swap (either by explicitly providing one or by ensuring it has noexcept move semantics), then you'll increase your chances of finding that sooner rather than later.

huangapple
  • 本文由 发表于 2023年4月6日 22:04:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75950431.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定