交换功能的好处?

Rob*_*Rob 31 c++ swap stl

浏览一些C++问题我经常看到一些STL友好类应该实现一个swap函数的评论(通常作为朋友.)有人可以解释一下它带来了什么好处,STL如何适应这个以及为什么这个函数应该实现为friend

Yac*_*oby 25

对于大多数类,默认交换很好,但是,默认交换在所有情况下都不是最佳的.最常见的例子是使用Pointer to Implementation惯用语的类.与默认交换一样,大量内存会被复制,如果是专门的交换,只需交换指针就可以显着加快速度.

如果可能,它不应该是类的朋友,但是它可能需要访问您可能不希望在类API中公开的私有数据(例如,原始指针).


Mar*_*ork 23

标准版本的std :: swap()适用于大多数可分配的类型.

void std::swap(T& lhs,T& rhs)
{
    T tmp(lhs);
    lhs = rhs;
    rhs = tmp;
} 
Run Code Online (Sandbox Code Playgroud)

但它不是一个最佳实现,因为它调用复制构造函数,然后调用赋值运算符.

通过为您的类添加您自己的std :: swap()版本,您可以实现swap()的优化版本.

例如std :: vector.上面定义的默认实现非常昂贵,因为您需要复制整个数据区域.可能会释放旧数据区域或重新分配数据区域,并在复制的每个项目上调用包含类型的复制构造函数.一个专门的版本有一个非常简单的方法来做std :: swap()

// NOTE this is not real code.
// It is just an example to show how much more effecient swaping a vector could
// be. And how using a temporary for the vector object is not required.
std::swap(std::vector<T>& lhs,std::vector<T>& rhs)
{
    std::swap(lhs.data,rhs.data);  // swap a pointer to the data area
    std::swap(lhs.size,rhs.size);  // swap a couple of integers with size info.
    std::swap(lhs.resv,rhs.resv);
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您的类可以优化swap()操作,那么您应该这样做.否则将使用默认版本.

我个人喜欢将swap()实现为非投掷成员方法.然后提供std :: swap()的专用版本:

class X
{
    public:
        // As a side Note:
        //    This is also useful for any non trivial class
        //    Allows the implementation of the assignment operator
        //    using the copy swap idiom.
        void swap(X& rhs) throw (); // No throw exception guarantee
};


  // Should be in the same namespace as X.
  // This will allows ADL to find the correct swap when used by objects/functions in
  // other namespaces.
  void swap(X& lhs,X& rhs)
  {
     lhs.swap(rhs);
  } 
Run Code Online (Sandbox Code Playgroud)

  • 从C++ 11开始,"std :: swap()`的标准版本已经改为使用`std :: move()`用于移动构造类,我认为应该编辑这个答案以反映这一点. (3认同)

sth*_*sth 17

如果你想交换(例如)两个向量而不了解它们的实现,你基本上必须做这样的事情:

typedef std::vector<int> vec;

void myswap(vec &a, vec &b) {
   vec tmp = a;
   a = b;
   b = tmp;
}
Run Code Online (Sandbox Code Playgroud)

如果a并且b包含许多元素,这是无效的,因为所有这些元素都被复制a,btmp.

但是,如果交换函数知道并且可以访问向量的内部,则可能有更高效的实现:

void std::swap(vec &a, vec &b) {
   // assuming the elements of the vector are actually stored in some memory area
   // pointed to by vec::data
   void *tmp = a.data;
   a.data = b.data;
   b.data = tmp;
   // ...
}
Run Code Online (Sandbox Code Playgroud)

在这个实现中,只需要复制几个指针,而不是像第一个版本中那样复制所有元素.由于此实现需要访问向量的内部,因此它必须是友元函数.


Pie*_*ter 10

我把你的问题解释为基本上三个不同(相关)的问题.

  1. 为什么STL需要交换?
  2. 为什么要实现专门的交换(iso依赖于默认值swap)?
  3. 为什么要把它作为朋友实施?

为什么STL需要交换?

STL友好类需要的原因swapswap在许多STL算法中用作原始操作.(例如reverse,sort,partition等使用典型地实施swap)

为什么要实现专门的交换(iso依赖于默认值swap)?

你的问题的这部分已经有很多(好的)答案.基本上,了解类的内部经常允许您编写更加优化的swap函数.

为什么要把它作为朋友实施?

STL算法将始终将swap作为自由函数调用.所以它需要作为非成员函数可用才有用.
并且,因为当你可以使用内部结构的知识来编写更有效的交换时,编写自定义交换是唯一有益的,这意味着你的自由函数将需要访问你的类的内部,因此是朋友.

基本上,它不具备成为朋友,但如果它不需要成为朋友,通常有没有理由要么实现自定义交换.

请注意,您应确保自由函数与您的类位于同一名称空间内,以便STL算法可以通过Koening查找找到您的自由函数.

  • STL不需要在任何算法中使用`swap()`.许多算法倾向于使用`std :: iter_swap()`,它可能使用或不使用`std :: swap()`. (2认同)

Igo*_*aka 9

交换功能的另一个用途是帮助例外安全代码:http://www.gotw.ca/gotw/059.htm