使用std::sort时如何理解这个结果?

How to understand this result when using std::sort?

我正在尝试实施 PP class。请先帮助检查以下不完整的代码:

template <typename E>
class PP{
public:
    struct Point2D {
        static int used_count;
        E _x;
        E _y;
        Point2D() : _x(0), _y(0) {
            used_count++;
            std::cout << "Point2D(), used_count = " << used_count << "\n";
        }
        virtual ~Point2D() {
            used_count--;
            std::cout << "~Point2D(), used_count = " << used_count << "\n";
        }
    };

    std::vector<Point2D> _points;
    int _size;

    PP(int size) : _size(size) {
        _points.resize(_size);
        std::cout << "PP(int size)\n";
    }
    PP(E points[][2], int size)
        : PP(size) {  // Nx2 points
        for (int i = 0; i < _size; i++) {
            _points[i]._x = points[i][0];
            _points[i]._y = points[i][1];
        }
        std::cout << "PP(E points[][2])\n";
    }

    virtual ~PP() {
        std::cout << "~PP()\n";
    }

    void Print(const std::string& title) {
        std::cout << title << "\n";
        for (auto iter = _points.begin(); iter != _points.end(); iter++) {
            const Point2D& p = *iter;
            std::cout << p._x << ", " << p._y << "\n";
        }
    }

    void DoSort() {
        std::sort(_points.begin(), _points.end(), [](const Point2D& l, const Point2D& r){ 
            return (l._y > r._y) || (l._y == r._y && l._x > r._x);
        });
    }
};


template<> int PP<int>::Point2D::used_count = 0;
int main() {
      int arr[][2] = {{1, 2},
                      {3, 4},
                      {5, 1},
                      {1, 5},
                      {2, 8},
                      {9, 1},
                      {6, 4},
                      {5, 6}};
      int size = sizeof(arr) / sizeof(arr[0]);

      if (1) {
          PP<int> *t = new PP<int>(arr, size);

          // test sort
          {
              t->Print("before sort");
              t->DoSort();
              t->Print("after sort");
          }

          delete t;
      }
}

结果如下:

  Point2D(), used_count = 1
  Point2D(), used_count = 2
  Point2D(), used_count = 3
  Point2D(), used_count = 4
  Point2D(), used_count = 5
  Point2D(), used_count = 6
  Point2D(), used_count = 7
  Point2D(), used_count = 8
  PP(int size)
  PP(E points[][2])
  before sort
  1, 2
  3, 4
  5, 1
  1, 5
  2, 8
  9, 1
  6, 4
  5, 6
  ~Point2D(), used_count = 7
  ~Point2D(), used_count = 6
  ~Point2D(), used_count = 5
  ~Point2D(), used_count = 4
  ~Point2D(), used_count = 3
  ~Point2D(), used_count = 2
  ~Point2D(), used_count = 1
  after sort
  2, 8
  5, 6
  1, 5
  6, 4
  3, 4
  1, 2
  9, 1
  5, 1
  ~PP()
  ~Point2D(), used_count = 0
  ~Point2D(), used_count = -1
  ~Point2D(), used_count = -2
  ~Point2D(), used_count = -3
  ~Point2D(), used_count = -4
  ~Point2D(), used_count = -5
  ~Point2D(), used_count = -6
  ~Point2D(), used_count = -7

我的问题是,在DoSort函数中,我只是使用了Point2Dreference,请问为什么会调用Point2D的析构函数std::sort 例程?发生了什么?你能帮忙给点建议吗?提前致谢。

您没有测量调用的复制构造函数。您可以通过添加:

Point2D(Point2D const & p) : _x(p._x), _y(p._y) {
     used_count++;
     std::cout << "Point2D(), used_count = " << used_count << "\n";
}

如果你这样做,你会得到预期的 used_count

这是一个 demo

交换元素时,额外的副本在 std::sort 的内部创建,其中有 Point2D 的副本。

通常 std::sort 会在其内部使用移动函数,但您看到这些不必要的副本的原因是您没有为 class 定义 move。如果你这样做:

Point2D(Point2D&& p) : _x(p._x), _y(p._y) {
    std::cout << "Point2D(), used_count = " << used_count << "\n";
    used_count++;
}

Point2D& operator=(Point2D&&) = default;

你看到没有复制。但是,在调用 std::sort 时,used_count 仍将在 8 和 9 之间振荡。仍然有相同数量的临时文件被创建,但这些临时文件被移动而不是被复制,一般来说效率更高。对于这个特定的 class 实例化,可能没有太大的改进,因为它只包含 2 ints,但这是一个养成的好习惯。例如如果你实例化 PP 而不是 std::string 你可以获得相当大的效率提升。

这是一个demo