Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 排序并不总是调用std::swap_C++_Stl - Fatal编程技术网

C++ 排序并不总是调用std::swap

C++ 排序并不总是调用std::swap,c++,stl,C++,Stl,考虑以下代码: #include <algorithm> #include <iostream> #include <vector> namespace my_space { struct A { double a; double* b; bool operator<(const A& rhs) const { return this->a < rhs.a; } }; v

考虑以下代码:

#include <algorithm>
#include <iostream>
#include <vector>

namespace my_space
{

struct A
{
    double  a;
    double* b;
    bool operator<(const A& rhs) const
    {
        return this->a < rhs.a;
    }
};

void swap(A& lhs, A& rhs)
{
    std::cerr << "My swap.\n";
    std::swap(lhs.a, rhs.a);
    std::swap(lhs.b, rhs.b);
}

}

int main()
{
    const int n = 20;
    std::vector<my_space::A> vec(n);
    for (int i = 0; i < n; ++i) {
        vec[i].a = -i;
    }

    for (int i = 0; i < n; ++i) {
        std::cerr << vec[i].a << " ";
    }
    std::cerr << "\n";
    std::sort(vec.begin(), vec.end());
    for (int i = 0; i < n; ++i) {
        std::cerr << vec[i].a << " ";
    }
    std::cerr << "\n";
}
#包括
#包括
#包括
名称空间my_空间
{
结构A
{
双a;
双*b;
布尔运算符std::cerr我修改了代码,使其更加详细。20个元素的排序使用许多交换,使用赋值结束拷贝。4个元素的排序只使用赋值和拷贝。我不知道规范,但可能需要继续

#include <algorithm>
#include <iostream>
#include <vector>

namespace my_space
{

struct A
{
    double  a;
    double* b;
    A()
        : a(0)
        , b(NULL)
    { }
    A(const A &rhs)
        : a(rhs.a)
        , b(rhs.b)
    {
        std::cerr << "copy" << std::endl;
    }
    A& operator=(A const &rhs)
    {
        if(this==&rhs)
                return *this;
        a = rhs.a;
        b = rhs.b;
        std::cerr << "=" << std::endl;
        return *this;
    }
    bool operator<(const A& rhs) const
    {
        return this->a < rhs.a;
    }
};

void swap(A& lhs, A& rhs)
{
    std::cerr << "My swap.\n";
    std::swap(lhs.a, rhs.a);
    std::swap(lhs.b, rhs.b);
}

} // namespace my_space

int main()
{
    const int n = 20;

        std::cerr << "=== TEST CASE: n = " << n << std::endl;
    std::cerr << "=== FILL ===" << std::endl;
    std::vector<my_space::A> vec(n);
    for (int i = 0; i < n; ++i) {
        vec[i].a = -i;
    }

    std::cerr << "=== PRINT ===" << std::endl;
    for (int i = 0; i < n; ++i) {
        std::cerr << vec[i].a << " ";
    }
    std::cerr << "\n";

    std::cerr << "=== SORT ===" << std::endl;
    std::sort(vec.begin(), vec.end());

    std::cerr << "=== PRINT ===" << std::endl;
    for (int i = 0; i < n; ++i) {
        std::cerr << vec[i].a << " ";
    }
    std::cerr << "\n";
}


对于小范围,GCC的stdlibc++(和其他标准库实现)中的
std::sort
实现出于性能原因而递归到插入排序(在小范围内比快速排序/插入排序更快)

GCC的插入排序实现不通过
std::swap
进行交换–相反,它一次移动整个值范围,而不是单独交换,从而潜在地节省性能。相关部分如下(
bits/stl_algo.h:2187
,GCC 4.7.2):


根据类型的不同,交换可能比移动赋值更昂贵(在C++98中是简单赋值)。标准库没有任何方法检测这些情况。至少在C++11中,解决方案是明确的:为实现交换的所有类实现移动赋值运算符。

应该会有所帮助。顺便问一下,为什么要使用
std::cerr
进行正常输出?我不使用
cerr
进行正常输出。我使用
cout
进行正常输出tput和
cerr
用于错误消息、诊断和调试。在这种情况下,我想我本可以使用
cout
+1这个问题让我进行了大量的挖掘,尽管我知道了原因的大致轮廓。顺便说一句:SGI的排序使用,这在某种程度上改变了策略。您可能需要实现堆排序,因此可以使用仅交换。要进行有效的稳定排序,您需要副本和/或分配。有一种称为“就地合并排序”的就地稳定排序,它可能只使用交换,但速度稍慢(nlognlogn,而不是n*logn)但是,std::sort无论如何都不必是稳定的。因此,交换与不交换并不影响此处的复杂性。对于20个元素,我自己的堆排序实现使用了62次交换,其他什么都没有。G++的STL使用了99次操作(35次复制、19次赋值、10次交换、35次删除)不要认为它是武器级的,它缺乏很多可用性特征。链接:所以如果移动比你的类型交换更昂贵,那么GCC的策略是悲观的,但那是“你自己的错误”。为了优化交换而不是优化移动,对吗?@SteveJessop是的,是的。谢谢你!谢谢你,Steve,在评论中提出了一个好问题!只是为了给我(和其他人)澄清一下。“优化移动”意味着写移动构造器,对吗?@Ben你真的想要一个移动任务。
=== TEST CASE: n = 4
=== FILL ===
copy
copy
copy
copy
=== PRINT ===
0 -1 -2 -3
=== SORT ===
copy
=
=
copy
=
=
=
copy
=
=
=
=
=== PRINT ===
-3 -2 -1 0
=== TEST CASE: n = 20
=== FILL ===
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
=== PRINT ===
0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19
=== SORT ===
copy
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
=
copy
=
copy
=
copy
=
=== PRINT ===
-19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0
typename iterator_traits<_RandomAccessIterator>::value_type
  __val = _GLIBCXX_MOVE(*__i);
_GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1);
*__first = _GLIBCXX_MOVE(__val);
  first           i
+---+---+---+---+---+---+
| b | c | d | e | a | f |
+---+---+---+---+---+---+
                  |
  <---------------+


  first           i
+---+---+---+---+---+---+
| --> b-> c-> d-> e-> f |
+---+---+---+---+---+---+


  first           i
+---+---+---+---+---+---+
| a | b | c | d | e | f |
+---+---+---+---+---+---+
  ^