gpt4 book ai didi

c++ - 如何使用 std::sort() 对指向值的 vector 进行排序?

转载 作者:行者123 更新时间:2023-11-30 04:48:58 25 4
gpt4 key购买 nike

已有帖子sorting vector of pointers但这不是关于指针 vector ,而是关于引用指针 vector 。

3个整数被放入std::vector<int*>然后根据指针后面的值进行排序。

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

int main() {
int a = 3;
int b = 2;
int c = 1;

std::vector<int*> vec;
vec.emplace_back(&a);
vec.emplace_back(&b);
vec.emplace_back(&c);

std::sort(vec.begin(), vec.end(), [](const int* a, const int* b) {
return *a < *b;
});

std::cout << "vec = " << *vec[0] << ", " << *vec[1] << ", " << *vec[2] << '\n';
std::cout << "abc = " << a << ", " << b << ", " << c << '\n';
}

然而,似乎只有 vector 被排序,如输出所示:

vec = 1, 2, 3 
abc = 3, 2, 1

我认为原因是std::sort() ,在正确比较的同时,只是分配地址而不是值。这里有什么问题?为什么我不能对这个指向值的 vector 进行排序?

下一部分相当长篇大论,因为它展示了我解决这个问题的方法。一项简单的任务表明自己相当复杂,令人沮丧。 @Bathsheba's answer指出这是不可能的。所以接下来的部分,最初被认为是我的尝试的展示,现在可能被认为是为什么不可能的原因。


我的想法是创建一个指针类包装器来提供我自己的构造函数和赋值运算符。 std::sort()如果容器的大小很小(在我的系统上为 <= 32),则行为会有所不同,但在这两种情况下都会发生分配和移动——因为来自 _Insertion_sort_unchecked 的这个小片段(来自 <algorithm> )功能展示。

(_BidIt == std::vector<int*>::iterator_Iter_value_t<_BidIt> == int* )

_BidIt _Insertion_sort_unchecked(_BidIt _First, const _BidIt _Last, _Pr _Pred)
{ // insertion sort [_First, _Last), using _Pred
if (_First != _Last)
{
for (_BidIt _Next = _First; ++_Next != _Last; )
{ // order next element
_BidIt _Next1 = _Next;
_Iter_value_t<_BidIt> _Val = _STD move(*_Next);

if (_DEBUG_LT_PRED(_Pred, _Val, *_First))
{ // found new earliest element, move to front
_Move_backward_unchecked(_First, _Next, ++_Next1);
*_First = _STD move(_Val);

让我们上一个类assignement_pointer它的行为类似于指针,只是它分配的是值而不是地址。

template<typename T>
class assignement_pointer {
public:
assignement_pointer(T& value) {
this->m_ptr = &value;
std::cout << "<T>& constructor\n";
}
assignement_pointer(const assignement_pointer& other) {
this->m_ptr = other.m_ptr;
std::cout << "copy constructor\n";
}
assignement_pointer(assignement_pointer&& other) {
std::cout << "move assignement constructor >> into >> ";
*this = std::move(other);
}
assignement_pointer& operator=(const assignement_pointer& other) {
*this->m_ptr = *other.m_ptr;
std::cout << "copy assignement operator\n";
return *this;
}
assignement_pointer& operator=(assignement_pointer&& other) {
std::swap(this->m_ptr, other.m_ptr);
std::cout << "move assignement operator\n";
return *this;
}
T& operator*() {
return *this->m_ptr;
}
const T& operator*() const {
return *this->m_ptr;
}
private:
T* m_ptr;
};

如您所见,还有临时的 std::cout查看 std::sort() 时调用了哪些构造函数/赋值运算符主要是:

    ///...
std::vector<assignement_pointer<int>> vec;
vec.reserve(3);
vec.emplace_back(assignement_pointer(a));
vec.emplace_back(assignement_pointer(b));
vec.emplace_back(assignement_pointer(c));

std::cout << "\nsort()\n";
std::sort(vec.begin(), vec.end(), [](const assignement_pointer<int>& a, const assignement_pointer<int>& b) {
return *a < *b;
});

std::cout << "\nvec = " << *vec[0] << ", " << *vec[1] << ", " << *vec[2] << '\n';
std::cout << "abc = " << a << ", " << b << ", " << c << '\n';

给出输出:

<T>& constructor
move assignement constructor >> into >> move assignement operator
<T>& constructor
move assignement constructor >> into >> move assignement operator
<T>& constructor
move assignement constructor >> into >> move assignement operator

sort()
move assignement constructor >> into >> move assignement operator
move assignement operator
move assignement operator
move assignement constructor >> into >> move assignement operator
move assignement operator
move assignement operator
move assignement operator

vec = 1, 2, 3
abc = 3, 2, 1
  • std::sort()仅调用移动函数。
  • 再次,vec已排序但未排序 a , b , c

最后一点是有道理的,因为只有移动函数被称为复制赋值运算符 assignement_pointer& operator=(const assignement_pointer& other); (执行值分配)永远不会被调用。可以删除不必要的复制构造函数和赋值运算符:

template<typename T>
class assignement_pointer {
public:
assignement_pointer(T& value) {
this->m_ptr = &value;
}
assignement_pointer(const assignement_pointer& other) = delete;
assignement_pointer& operator=(const assignement_pointer& other) = delete;
assignement_pointer(assignement_pointer&& other) {
std::cout << "move assignement constructor >> into >> ";
*this = std::move(other);
}
assignement_pointer& operator=(assignement_pointer&& other) {
std::swap(this->m_ptr, other.m_ptr);
std::cout << "move assignement operator\n";
return *this;
}
T& operator*() {
return *this->m_ptr;
}
const T& operator*() const {
return *this->m_ptr;
}
private:
T* m_ptr;
};

现在std::sort()内部流程相当复杂,但最终归结为在类似 std::swap() 的操作中失败:

 int main() {
int a = 3;
int b = 2;

std::vector<assignement_pointer<int>> vec;
vec.reserve(2); //to avoid re-allocations
vec.emplace_back(assignement_pointer(a));
vec.emplace_back(assignement_pointer(b));

std::cout << "swap()\n";

assignement_pointer<int> ptr_a{ a };
assignement_pointer<int> ptr_b{ b };

std::swap(ptr_a, ptr_b);

std::cout << "\nptrs = " << *ptr_a << ", " << *ptr_b << '\n';
std::cout << "a, b = " << a << ", " << b << '\n';
}

如输出所示:

move assignement constructor >> into >> move assignement operator
move assignement constructor >> into >> move assignement operator
swap()
move assignement constructor >> into >> move assignement operator
move assignement operator
move assignement operator

ptrs = 2, 3
a, b = 3, 2

就是那种只切换指针而不切换原始变量的情况。 std::swap基本上是

_Ty _Tmp = _STD move(_Left);
_Left = _STD move(_Right);
_Right = _STD move(_Tmp);

解释

move assignement constructor >> into >> move assignement operator
move assignement operator
move assignement operator

移动赋值运算符只是交换指针,因此创建一个临时变量不会做任何事情。我看到了两种可能的解决方案:

  • 使移动赋值运算符不交换指针而是交换值。
  • 实现我自己的 swap()为类(class)

但两者都不起作用。

  • 移动赋值运算符不能交换值,因为初始的 m_ptr来自 this->类总是 nullptr我宁愿不取消引用它。
  • std::sort()从不使用 std::swap()而不是 std::move()来自各地。 (正如 _Insertion_sort_unchecked 已经部分看到的那样)。

最佳答案

您需要滚动自己的排序函数来执行此操作。

回调 lambda 用于评估排序,但您需要调整执行实际元素交换的部分:C++ 标准库 sort 不支持您这样做。

幸运的是,快速排序没有任何花里胡哨的东西(例如预随机化),只需要几十行,所以这不是一项特别繁重的任务。

关于c++ - 如何使用 std::sort() 对指向值的 vector 进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55594375/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com