【问题标题】:Is there a way to keep references/pointers to objects in unordered_set?有没有办法在 unordered_set 中保留对对象的引用/指针?
【发布时间】:2020-07-09 09:06:55
【问题描述】:

我有几个class A 的对象。在其他一些class B 中,我想保留class A 的unordered_set 对象集。请注意,class B 的对象因此包含一个集合,该集合可能指向(某些)与另一个集合相同的class A 对象。要求这些class A 对象永远不会被复制或任何东西,因为它们包含应该由class Bclass A 的不同对象使用和更改(共享使用)的成员数据。

首先,由于我来自 C,我想只是使用指向对象的指针作为集合中的值。但是,在编码时,我发现我现在还需要传递重写的哈希和相等功能,因为我必须比较 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() 之间的区别。我不明白“复制与移动”是什么意思。

TLDR:为了在集合或映射中保留对用户定义类的对象的引用,在这种情况下是否可以使用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;
};

【问题讨论】:

  • 指针和引用在 C++ 中都有其用途。您需要了解每个应该用于什么,以及何时不应该使用。对于“指针或引用”,C++ 中没有“一刀切”的答案。事实上,每个 C++ 类型的问题中的“最好做 X 还是 Y”都有相同的答案:“是”。
  • @SamVarshavchik 看来我的问题还不够清楚。我相信我充分意识到指针和引用之间的区别,我也相信我的问题表明了这一点。在这方面,当然非常感谢有关如何提高问题清晰度的任何反馈。我的意思是特别询问如何使用指针、引用或对象作为值类型,以及对于问题中描述的用例,哪一个更好。
  • 您可能知道它们之间的区别,但您问这个问题是因为您不知道什么时候“最好”使用其中一个,这是我特别提到的在我的评论中。此外,如果您尝试在 unordered_set 中实际使用引用,您......将不太可能成功。在某些时候,迟早你会意识到你不能在 C++ 中做到这一点,你能做的最多就是使用std::reference_wrapper。所以,在你开始思考哪个是“更好的选择”之前,看起来你还有更多的学习要做,在这里。
  • @SamVarshavchik 谢谢。我偶然发现了您在评论中描述的问题,并尝试使用std::reference_wrapper 实施解决方案。你提出了一个很好的观点,这在原始问题中并不清楚,我将对其进行编辑。话虽如此,我想强调我并不是在寻找任何一般的“最佳”解决方案,但我相信我已经提供了一个足够具体的用例来要求一个特定的解决方案 at all 因为我找不到在任何情况下都有效的。您是否建议我继续尝试使用 reference_wrapper? 在这种情况下是首选模式吗?
  • 也许吧。不能仅根据给定的信息就是否应该使用指针、引用或离散对象做出明智的决定。这取决于很多很多其他因素。 C++ 是当今使用的最复杂的通用编程语言。例如,仅基于显示的代码,答案将是“不要使用指针或引用,只需将它们存储在集合中”。当您在显示的代码中再添加一行时,答案可能会有所不同,原因可能有很多。这就是为什么 stackoverflow.com 上没有人能真正给你答案的原因。

标签: c++ pointers reference stl unordered-set


【解决方案1】:

免责声明:我是 OP,我是 C++ 新手。我的代码现在按预期编译和运行,虽然我相信以下所有信息都是正确的,但请留下评论以通知我任何错误。

对于那些感兴趣的人,我最终在 A 类中创建了两个公共仿函数(内部,因为我需要访问私有成员(使用 friend 也是一种选择))并在 @ 的声明中使用它们987654324@。对于我使用 A* 的类型。更好的解决方案可能是智能指针,但我对这一切都很陌生,所以我还没有详细研究过这些。

关于std::unordered_set我学到了以下几点:

  1. 默认的相等和散列行为仅适用于here 列出的类型。
  2. 如果您需要其他任何东西,您有 3 个选项:使用某种指向类型的指针(可以是原始的,std::shared_ptrstd::unique_ptr,...),使用 std::reference_wrapper&lt;T&gt;,或使用类型本身.请注意,A&amp; 之类的引用不允许作为 std::unordered_set 的 value_type,因此是包装器。
  3. 在前两个选项中,默认实现(如果有)不会“向下级联”以使用您可能为您的类型定义的任何operator ==。在第 5 点中提出了一个解决方案。
  4. 在最后一个选项中,您的类型的operator == 用作默认的'equaller'。在这里只需要一个哈希器的定义。但是,您应该警惕std::unordered_set::insert() 创建插入元素的副本,因此如果它包含静态分配的成员数据,则应确保在开始复制该类型的实例时程序仍能正常运行。我认为这是最不冗长的解决方案,也是我找到最多示例的解决方案。 (使用std::unordered_set::emplace() 可能是整个复制问题的解决方案,但我还没有完全弄清楚。)
  5. 一般来说,'hasher' 和 'equalling' 功能可以通过两种方式提供:通过定义std::hash&lt;T&gt;和/或std::equal_to&lt;T&gt;,或者通过创建用于这些目的的函子。有关如何做到这一点的更多信息here。它们本质上做同样的事情,所以它们可以互换。如第 4 点所述,当您存储直接类型时,还有 1 个选项,您也可以使用 operator ==,然后在声明 std::unordered_set 时无需指定任何“相等”。李>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-14
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    相关资源
    最近更新 更多