如何使指针在 std::set 中有效?

How can make pointer valid in std::set?

提问人:nick 提问时间:3/16/2021 最后编辑:463035818_is_not_an_ainick 更新时间:3/16/2021 访问量:113

问:

我有一个自定义的结构,我重载运算符>:

struct A {
  A(int a) : a_(a) {}
  int a_;
  friend operator > (const A& a) const {
    return a_ > a.a_; 
  }
};

所以我可以将这个结构推入 STL 容器集:

std::set<A> s;
s.insert(A(3));
s.insert(A(5));
s.insert(A(4));

但是我正在做一项大任务,这意味着复制操作对我来说成本很高。

所以,我想用元素类型的指针构建一个集合,如下所示:

std::set<A*>s;
A a(3); A b(5); A c(4);
s.insert(&a); s.insert(&b); s.insert(&c);

但是我发现它无法保持顺序,有什么方法可以按元素指针保持顺序吗?

或者,我怎样才能将元素保存在有序的容器中,而不进行复制并具有良好的性能?

C++ 设置 std

评论

2赞 François Andrieux 3/16/2021
您可以使用 instead 代替就地构造对象,这样就不会有副本。emplaceinsert
3赞 interjay 3/16/2021
集合使用 ,而不是 。对于指针,您需要提供自定义比较器。operator<operator>
1赞 rustyx 3/16/2021
别这样。考虑缓存位置。使用指针的额外间接将降低性能。代替以避免复制/移动。s.emplace(3);s.insert(A(3));
1赞 Lukas-T 3/16/2021
第二段代码也要复杂得多,因为您需要正确管理所指向对象的生存期。简单地存储局部变量的地址可能会很糟糕。
1赞 Caleth 3/16/2021
不要专注于“最佳性能”。专注于制定一个计算您想要的结果的程序。如果当你运行它时,它被证明太慢了,那么测量慢的部分是什么,并询问如何加快速度。

答:

3赞 m88 3/16/2021 #1

使用自定义比较器:

#include <iostream>
#include <set>

struct CustomCmp {
    bool operator()(const int* lhs, const int* rhs) const { 
        return *lhs < *rhs;
    }
};

int main()
{
    int arr[] = { 3, 1, 4 };

    std::set<int*, CustomCmp> mySet;
    mySet.insert(&arr[0]);
    mySet.insert(&arr[1]);
    mySet.insert(&arr[2]);

    for (auto& el: mySet) std::cout << *el << ' '; // 1, 3, 4

    return 0;
}

https://godbolt.org/z/zGc1a3

评论

0赞 nick 3/16/2021
感谢 M88,但与使用 EmPlace 相比性能如何?
0赞 m88 3/16/2021
如果你的 A 类有一个 move-constructor,并且大致等价,否则只会复制 .(对指针来说根本没有区别)s.insert(A(n))s.emplace(n);insertA(n)
0赞 m88 3/16/2021
@FrançoisAndrieux 我的意思是 [如果您想要一组 T* 像 T 一样排序,那么] 使用自定义比较器。话虽如此,除非 T 是我怀疑这真的是 OP 需要的,否则我同意。std::array<double,1'000'000>
0赞 François Andrieux 3/16/2021
@m88 对不起,我标记了错误的用户。我的意思是标记尼克。编辑:我用正确的@转发了我的评论。
0赞 François Andrieux 3/16/2021
@nick 您正在执行所谓的过早优化。您有两个类似的解决方案,目前尚不清楚哪种解决方案最适合您的特定用例。别担心,这是一个细节。使用最简单、最安全的解决方案,这是迄今为止最容易使用和最安全的解决方案。std::set<T>