使用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
函数中,我只是使用了Point2D
的reference
,请问为什么会调用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 int
s,但这是一个养成的好习惯。例如如果你实例化 PP
而不是 std::string
你可以获得相当大的效率提升。
这是一个demo。
我正在尝试实施 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
函数中,我只是使用了Point2D
的reference
,请问为什么会调用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 int
s,但这是一个养成的好习惯。例如如果你实例化 PP
而不是 std::string
你可以获得相当大的效率提升。
这是一个demo。