如何处理谓词/比较器/函子失效的问题? < >使用C++容器时(如 STD::代码> STD::unOrdEdjPad >等)人们如何处理传递给容器的函子(代号> STD::, STD::HASH < /代码>等)的情况下,在调用容器时可能会失效(例如,指针)?

如何处理谓词/比较器/函子失效的问题? < >使用C++容器时(如 STD::代码> STD::unOrdEdjPad >等)人们如何处理传递给容器的函子(代号> STD::, STD::HASH < /代码>等)的情况下,在调用容器时可能会失效(例如,指针)?,c++,C++,为便于说明,一个示例可能是具有如下内部指针的对象: struct Hash // or Less, etc. { std::vector<size_t>::iterator p; size_t operator()(size_t i) { return p[i]; } }; std::unordered_set<size_t, Hash> container; // or std::map or whatever struct Hash//或更少,

为便于说明,一个示例可能是具有如下内部指针的对象:

struct Hash  // or Less, etc.
{
    std::vector<size_t>::iterator p;
    size_t operator()(size_t i) { return p[i]; }
};

std::unordered_set<size_t, Hash> container;  // or std::map or whatever
struct Hash//或更少,等等。
{
std::vector::迭代器p;
size_t运算符()(size_t i){返回p[i];}
};
std::无序的集合容器;//或者std::map或者其他什么
作为调用者,我知道成员失效将在何时发生,如果我有权访问内部谓词并可以覆盖它,我可以采取步骤纠正它,但我没有

我可以想象有几种方法可以解决这个问题:

  • 我可以存储指向容器对象的指针。这增加了一个间接寻址,并且在交换容器时仍然会中断,因此它并不能真正解决问题

  • 我可以使用
    共享\u ptr
    (或
    侵入式\u ptr
    等)向其有效负载添加间接寻址,以便在外部修复有效负载。这是可行的,但是额外的内存访问带来了我希望避免的(轻微的)性能损失

  • 我可以让我的谓词在构造时做一些黑客操作来“报告”它自己的地址,假设容器只维护谓词的一个副本。这似乎是最脆弱的,但它应该是最有效的


没有一个是好的,所以我想知道人们通常如何处理这个问题。这是一个已知的用例吗?有没有我没有看到的好的解决方案?

你可以使用
std::reference\u包装器
。它基本上是一个性能更好的指针。不进行任何分配:

#include <functional>
#include <unordered_map>
#include <vector>

struct Hash {
  std::vector<std::size_t>::iterator p;
  std::size_t operator()(std::size_t i) const noexcept { return p[i]; }
};

int main() {
  std::vector<std::size_t> vec{1, 2, 3, 4, 5};
  Hash hash{vec.begin()};

  std::unordered_map<int, int, std::reference_wrapper<Hash>> map(
      0, std::ref(hash));

  map[0] = 0;

  vec.push_back(6);  // likely invalidates

  hash.p = vec.begin();  // validated again

  map[1] = 1;
}
#包括
#包括
#包括
结构散列{
std::vector::迭代器p;
std::size_t运算符()(std::size_t i)const noexcept{return p[i];}
};
int main(){
向量向量{1,2,3,4,5};
散列哈希{vec.begin()};
std::无序的_映射(
0,std::ref(散列));
map[0]=0;
vec.push_back(6);//可能无效
hash.p=vec.begin();//再次验证
map[1]=1;
}

我可能是错的或极度偏执,但我认为大多数
函数使用有状态谓词的定义是不正确的。在某些情况下,我们不能保证系统的有序或非并发状态calls@SwiftFrayay馅饼:有趣,但请注意,在这种情况下,我不需要订单或并发保证,或真正的任何保证,在中间的呼叫这件事。内部迭代器/指针所引用的内容在对容器的任何调用期间都保持完全不变。我只需要在调用之间做一些事情。你可以存储对某个迭代器的“引用”,你可以控制
std::reference\u wrapper
的类型
p
p[I]
对于迭代器来说不是有效的语法afaik@user541686它显然是针对随机访问迭代器的。我不知道