有没有办法将 references/pointers 保留到 unordered_set 中的对象?
Is there a way to keep references/pointers to objects in unordered_set?
我有几个 class A
的对象。在其他一些 class B
中,我想保留 unordered_set 个 class A
的对象。请注意,class B
的对象因此包含一个集合,该集合可能指向(某些)与另一个集合相同的 class A
对象。要求永远不要复制这些 class A
对象或任何东西,因为它们包含应该由 class B
和 [=13] 的不同对象使用和更改(使用中共享)的成员数据=].
首先,由于我来自 C,我想只使用指向对象的指针作为集合中的值。然而,在编码时我发现我现在还需要传递覆盖的哈希和相等功能,因为我必须比较 class A 的对象是否与 class A
的私有成员相等。因此,哈希函数需要是 class A
.
的 public 成员函数
不过我想知道,因为 std::unordered_set::insert()
似乎采用 引用 value_type,是否可以只使用 A 作为值键入 std::unordered_set
。这将使代码更容易一些,因为它默认使用 class A
中已经实现的 == operator
。但是,我不确定 std::unordered_set::insert()
是否复制了您传递给它的对象。似乎没有,但是 value_type 仍然是 A,而不是 A&。
我也看不出std::unordered_set::insert()
和std::unordered_set::emplace()
的区别。我不明白 "copy vs move" 是什么意思。
TLDR:要在集合或映射中保留对用户定义的 classes 对象的引用,在这种情况下是否可以将 A*
用作 value_type?还是std::reference_wrapper<A>
?或者只是普通的 A
?
这是一个最小的可重现示例:
class A {
public:
bool operator== (A& other);
private:
B* b;
size_t id;
size_t someIntThatMustBeShared;
};
class B {
public:
std::unordered_set<A ? > as;
};
免责声明:我是 OP,我是 C++ 新手。我的代码现在按预期编译和运行,虽然我相信以下所有信息都是正确的,但请发表评论以通知我任何错误。
对于那些感兴趣的人,我最终在 class A 中创建了两个 public 仿函数(内部,因为我需要访问私有成员(使用 friend
也将是一个option)) 并在 std::unordered_set
的声明中使用它们。对于我使用 A* 的类型。更好的解决方案可能是智能指针,但我对这一切都是新手,所以我还没有详细研究这些。
我了解到以下关于 std::unordered_set
的事情:
- 默认的相等和散列行为仅针对列出的类型实现 here。
- 如果您需要其他任何东西,您有 3 个选择:使用某种指向类型的指针(是原始的,
std::shared_ptr
、std::unique_ptr
、...),使用 std::reference_wrapper<T>
,或使用类型本身。请注意,对于 std::unordered_set
,不允许像 A&
这样的引用作为 value_type,因此是包装器。
- 在前两个选项中,默认实现(如果有)不会'cascade down'使用您可能为您的类型定义的任何
operator ==
。在第 5 点中提出了解决方案。
- 在最后一个选项中,您的类型
operator ==
被用作默认值 'equaller'。在这里工作只需要一个散列器的定义。但是,您应该小心 std::unordered_set::insert()
创建插入元素的副本,因此如果它包含静态分配的成员数据,您应该确保在开始复制该类型的实例时您的程序仍然正常运行。我认为这是最不冗长的解决方案,也是我找到最多示例的解决方案。 (使用 std::unordered_set::emplace()
可能是整个复制问题的解决方案,但我还没有完全弄明白。)
- 通常,可以通过两种方式提供 'hasher' 和 'equalling' 功能:通过
std::hash<T>
and/or std::equal_to<T>
的定义,或通过为这些目的创建函子。有关如何执行此操作的更多信息 here。这些本质上做同样的事情,所以它们可以互换。如第 4 点所述,当您存储直接类型时还有 1 个其他选项,您也可以使用 operator ==
,然后在声明 [= 时不需要指定任何 'equaller' 11=].
我有几个 class A
的对象。在其他一些 class B
中,我想保留 unordered_set 个 class A
的对象。请注意,class B
的对象因此包含一个集合,该集合可能指向(某些)与另一个集合相同的 class A
对象。要求永远不要复制这些 class A
对象或任何东西,因为它们包含应该由 class B
和 [=13] 的不同对象使用和更改(使用中共享)的成员数据=].
首先,由于我来自 C,我想只使用指向对象的指针作为集合中的值。然而,在编码时我发现我现在还需要传递覆盖的哈希和相等功能,因为我必须比较 class A 的对象是否与 class A
的私有成员相等。因此,哈希函数需要是 class A
.
不过我想知道,因为 std::unordered_set::insert()
似乎采用 引用 value_type,是否可以只使用 A 作为值键入 std::unordered_set
。这将使代码更容易一些,因为它默认使用 class A
中已经实现的 == operator
。但是,我不确定 std::unordered_set::insert()
是否复制了您传递给它的对象。似乎没有,但是 value_type 仍然是 A,而不是 A&。
我也看不出std::unordered_set::insert()
和std::unordered_set::emplace()
的区别。我不明白 "copy vs move" 是什么意思。
TLDR:要在集合或映射中保留对用户定义的 classes 对象的引用,在这种情况下是否可以将 A*
用作 value_type?还是std::reference_wrapper<A>
?或者只是普通的 A
?
这是一个最小的可重现示例:
class A {
public:
bool operator== (A& other);
private:
B* b;
size_t id;
size_t someIntThatMustBeShared;
};
class B {
public:
std::unordered_set<A ? > as;
};
免责声明:我是 OP,我是 C++ 新手。我的代码现在按预期编译和运行,虽然我相信以下所有信息都是正确的,但请发表评论以通知我任何错误。
对于那些感兴趣的人,我最终在 class A 中创建了两个 public 仿函数(内部,因为我需要访问私有成员(使用 friend
也将是一个option)) 并在 std::unordered_set
的声明中使用它们。对于我使用 A* 的类型。更好的解决方案可能是智能指针,但我对这一切都是新手,所以我还没有详细研究这些。
我了解到以下关于 std::unordered_set
的事情:
- 默认的相等和散列行为仅针对列出的类型实现 here。
- 如果您需要其他任何东西,您有 3 个选择:使用某种指向类型的指针(是原始的,
std::shared_ptr
、std::unique_ptr
、...),使用std::reference_wrapper<T>
,或使用类型本身。请注意,对于std::unordered_set
,不允许像A&
这样的引用作为 value_type,因此是包装器。 - 在前两个选项中,默认实现(如果有)不会'cascade down'使用您可能为您的类型定义的任何
operator ==
。在第 5 点中提出了解决方案。 - 在最后一个选项中,您的类型
operator ==
被用作默认值 'equaller'。在这里工作只需要一个散列器的定义。但是,您应该小心std::unordered_set::insert()
创建插入元素的副本,因此如果它包含静态分配的成员数据,您应该确保在开始复制该类型的实例时您的程序仍然正常运行。我认为这是最不冗长的解决方案,也是我找到最多示例的解决方案。 (使用std::unordered_set::emplace()
可能是整个复制问题的解决方案,但我还没有完全弄明白。) - 通常,可以通过两种方式提供 'hasher' 和 'equalling' 功能:通过
std::hash<T>
and/orstd::equal_to<T>
的定义,或通过为这些目的创建函子。有关如何执行此操作的更多信息 here。这些本质上做同样的事情,所以它们可以互换。如第 4 点所述,当您存储直接类型时还有 1 个其他选项,您也可以使用operator ==
,然后在声明 [= 时不需要指定任何 'equaller' 11=].