【问题标题】:Efficient member pointers to other many objects指向其他许多对象的有效成员指针
【发布时间】:2021-04-12 15:24:04
【问题描述】:

假设我有一个图表,每个节点可能包含其他节点的值。假设计算该值的复杂性相当高( ~O(n^4) )。因此,我想存储为每个关系计算的值。我是 C++ 的新手,所以这就是我得到的(不包括构造函数等,为了简单起见使用 struct):

struct Node{
    long id_;
    const std::shared_ptr<Node> left_;
    const std::shared_ptr<Node> right_;
    const std::shared_ptr<Node> up_;
    const std::shared_ptr<Node> down_;
    std::unordered_map<std::shared_ptr<Node>, double> otherValues;
    
    double calculate(Node other);   // do math based on neighboring nodes
};

所以假设节点很少被删除但经常被添加,我想知道这是否是正确的方法?最初,我打算选择weak_ptr,因为所有节点也都存储在其他地方,但是每当我查找下一个节点(一直如此)时,我都必须转换为shared_ptr。我读过的这本书以及大多数文章都指出,如果可能的话,应该使用智能指针,但我想知道原始指针是否是这里更有效的方法。但是我不知道如何在这里实现这些,同时仍然安全。

任何建议将不胜感激!

编辑:我已更改 otherValues 以反映示例的其余部分。

【问题讨论】:

  • 循环引用会有问题。并且将您的成员设为const 也会使实际构建图表变得困难。
  • 容器应该拥有节点。节点不应相互拥有。
  • 原始指针是安全的,只要您在完成网络之前不删除任何节点。这些是结构指针,它们不需要拥有。
  • 包含节点的容器是什么样的?
  • 应该始终使用智能指针拥有指针。这些不是拥有的,因此它们应该使用原始指针。

标签: c++ performance class smart-pointers member


【解决方案1】:

很多时候,您希望通过坐标而不是相对访问节点,在这种情况下,您会得到这样的结果:

class Coordinate {
   int x, y;
};
enum Direction4 {
   Left, Up, Right, Down
};
Coordinate operator+(Coordinate, Direction4);

class Node {
    Graph* graph;
    Coordinate coordinate;
    Node* getAdjacent(Direction4 dir);
    double calculate(Node other);
};

class Graph {
    std::unordered_set<Coordinate, Node> nodes;
};

Node* Node::getAdjacent(Direction4 dir) {
    Coordinate coord = coordinate + dir;
    auto it = graph->nodes.find(coord);
    if (it == graph->nodes.end()) return nullptr;
    return &(it->second);
}

您可以通过坐标立即访问任何节点。图拥有节点,节点不拥有彼此。事实上,节点甚至不相互引用。这意味着我根本不必担心内存泄漏、重新分配或死指针。所有这些问题都完全消失了。

【讨论】:

  • 感谢您的回复!如果我的示例具有误导性,我很抱歉 - 没有我需要的坐标或实际方向,这只是示例。但我认为我明白你在说什么。在跳过有关原始指针的阅读之后,认为它们已经过时了,我想我现在必须加倍努力。 :/ 我的算法会创建数百万个节点,所以我很害怕内存泄漏和效率。
  • @Markstar:“避免原始指针”是常见的建议,它具有误导性,我讨厌它。相反,请避免使用new。而是使用std::make_unique 和标准容器,所有内存泄漏都成为过去。
  • 问题是节点会被移除,因为它不是一个固定的结构。我将不得不找到一种方法来验证一个对象是否仍然存在,这对于原始指针 afaik 是不可能的。
  • @Markstar:我的代码没有这个问题。如果一个节点被删除,它就不再存在。如果节点被删除,getAdjacent 将简单地开始返回 null。这是可能的因为节点之间没有任何直接引用。
猜你喜欢
  • 1970-01-01
  • 2014-01-02
  • 2011-05-17
  • 1970-01-01
  • 2016-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多