【问题标题】:Template iterators, dereferencing, and typedef in C++C++ 中的模板迭代器、取消引用和 typedef
【发布时间】:2016-08-07 02:21:06
【问题描述】:

我正在处理的程序中收到奇怪的结果,但我不知道错误出在哪里或为什么会出现错误。我正在研究一个使用模板化迭代器的模板化四叉树类。即使我的函数似乎工作正常,它也不会返回它找到的值。

这是我的基本四叉树类:

template <class number_type, class label_type>
class QuadTree {
public:
    // CONSTRUCTORS
    QuadTree() : size_(0), root_(NULL) {}

    // ACCESSORS
    unsigned int size() const { return size_; }

    typedef DepthIterator<number_type, label_type> iterator;

    iterator begin() const {
        return root_;
    }
    iterator end() const { return iterator(NULL); }

    // This is the function not returning the expected value 
    iterator find(number_type x, number_type y, Node<number_type, label_type>* parent = NULL) {
        if (parent == NULL) {
            // start at the root, if equal return, otherwise call recursively
            if (root_->pt.x == x && root_->pt.y == y) { return iterator(root_); }
            else {
                return find(x, y, root_);
            }
        }
        else {
            int quadrant;
            // find the quadrant of the point
            if (x < parent->pt.x && y < parent->pt.y) {
                quadrant = 0;
            }
            else if (x > parent->pt.x && y < parent->pt.y) {
                quadrant = 1;
            }
            else if (x < parent->pt.x && y > parent->pt.y) {
                quadrant = 2;
            }
            else if (x > parent->pt.x && y > parent->pt.y) {
                quadrant = 3;
            }
            // see if the quadrant is a branch or a leaf
            if (parent->children[quadrant] == NULL) {
                // child is a leaf and it matches the search
                if (x == parent->pt.x && y == parent->pt.y) { return iterator(parent); }
                // child is a leaf, but it does not match the search
                else { return iterator(NULL); }
            }
            else {
                // child is a branch, check if it's equal and return if it is, if not, continue on
                if (x == parent->pt.x && y == parent->pt.y) { return iterator(parent); }
                else { find(x, y, parent->children[quadrant]); }
            }
        }
    }
private:
    unsigned int size_;
    Node<number_type, label_type>* root_;
};

似乎我的 find 函数在我的四叉树上找到了正确的节点,因为我可以使用 std::cout 在父节点返回正确值之前打印出它。不过

return iterator(parent);

给我一​​个 NULL 值或点 (9,0),它不在我的四叉树中。

这是我的 DepthIterator 类:

template <class number_type, class label_type>
class DepthIterator {
public:
    // CONSTRUCTOR / COPY / ASSIGN / DECONSTRUCTOR
    DepthIterator() : ptr_(NULL) {}
    DepthIterator(Node<number_type, label_type>* n) : ptr_(n) {}
    DepthIterator(const DepthIterator& old) : ptr_(old.ptr_) {}
    ~DepthIterator() {}

    // OPERATORS
    DepthIterator& operator=(const DepthIterator& old) { ptr_ = old.ptr_; return *this; }
    const Point<number_type>& operator*() const { return ptr_->pt; }
    bool operator== (const DepthIterator& rgt) { return ptr_ == rgt.ptr_; }
    bool operator!= (const DepthIterator& rgt) { return ptr_ != rgt.ptr_; }

    // ACCESSORS
    label_type getLabel() const { return ptr_->label; }


private:
    Node<number_type, label_type>* ptr_;
};

也许我的复制或取消引用位是问题所在?我倾向于取消引用,因为我的 find 函数在使用该操作之前确实有效,但之后却不行。

这是我的节点类:

template <class number_type, class label_type>
class Node {
public:
    Node() {}
    Node(Point<number_type> p, label_type l) : pt(p), label(l) { parent = NULL; }

    Node& operator=(const Node& old) { pt = old.pt; label = old.label; parent = *old; return *this; }

    Point<number_type> pt;
    label_type label;
    Node<number_type, label_type>* children[4];
    Node<number_type, label_type>* parent;
};

我的主要功能将包含如下内容:

QuadTree<int, char>::iterator itr = test.find(20,10);
// the point (20,10) does exist in the quadtree
assert (itr != test.end());
assert (itr.getLabel() == 'A');
// both of these tests pass

const Point<int> &pt = *itr;
assert (pt.x == 20);
assert (pt.y == 10);
// both of these tests pass

QuadTree<int,char>::iterator itr = test.find(4,7);
// the point (4,7) does exist in the quadtree
assert (itr != test.end());
// this test fails however ^
assert (itr.getLabel() == 'B');

第一个测试有效,但第二个无效。我不确定这是因为第一个测试是根节点,而第二个测试不是,还是因为我在中间取消引用,或者完全是其他原因。我对 C++ 有点陌生,并且真的很难实现这一点。谁能解释为什么我的查找功能不起作用?

【问题讨论】:

  • 您可能应该最小化代码,只包含产生错误/奇怪行为的代码。
  • 如果 X 或 Y 等于 root_->pt.x 或 root_->pt.y 会发生什么
  • @rozina 我尽可能地将其修剪。部分原因是我不确定错误在哪里。

标签: c++ recursion iterator dereference quadtree


【解决方案1】:
 iterator find(number_type x, number_type y, Node<number_type, label_type>* parent = NULL) {
    if (parent == NULL) {
        // start at the root, if equal return, otherwise call recursively
        if (root_->pt.x == x && root_->pt.y == y) { return iterator(root_); }
        else {
            return find(x, y, root_);
        }
    }
    else {
        int quadrant;
        // find the quadrant of the point
        if (x < parent->pt.x && y < parent->pt.y) {
            quadrant = 0;
        }
        else if (x > parent->pt.x && y < parent->pt.y) {
            quadrant = 1;
        }
        else if (x < parent->pt.x && y > parent->pt.y) {
            quadrant = 2;
        }
        else if (x > parent->pt.x && y > parent->pt.y) {
            quadrant = 3;
        }
        // see if the quadrant is a branch or a leaf
        if (parent->children[quadrant] == NULL) {
            // child is a leaf and it matches the search
            if (x == parent->pt.x && y == parent->pt.y) { return iterator(parent); }
            // child is a leaf, but it does not match the search
            else { return iterator(NULL); }
        }
        else {
            // child is a branch, check if it's equal and return if it is, if not, continue on
            if (x == parent->pt.x && y == parent->pt.y) { return iterator(parent); }
            else { find(x, y, parent->children[quadrant]); }
        }
    }
}

如果 x == parent->pt.x 或 y == parent->pt.y 作为象限,问题是未定义的行为将是未定义的,因为没有一个 if 条件评估为真。在这种情况下,parent-&gt;children[quadrant] == NULL 的行为就像薛定谔的猫,可能是真的,也可能是假的。

一个可能的解决办法是:

if (x <= parent->pt.x && y <= parent->pt.y) {
        quadrant = 0;
    }
    else if (x > parent->pt.x && y <= parent->pt.y) {
        quadrant = 1;
    }
    else if (x <= parent->pt.x && y > parent->pt.y) {
        quadrant = 2;
    }
    else if (x > parent->pt.x && y > parent->pt.y) {
        quadrant = 3;
    }

【讨论】:

  • 我了解我的象限可能未定义,并按照您的建议进行了修复,但似乎并没有解决我的问题。该函数找到了正确的节点,但它似乎没有正确返回它。
  • 我明白了......我提出的解决方案应该只解决问题,如果它与四叉树的创建相关,对吧?你也验证了吗?据我目前了解你,你正在调试你的代码,它正确地遍历象限,直到你到达正确的节点,但返回值不等于它应该在函数内返回的值?
  • 是的,没错。它可以很好地遍历我的任何测试用例,但返回值不是应有的值。我写了一个测试函数,我在 find 内部调用并传递了 iterator(parent),它收到了正确的值,所以由于某种原因,它只是未能在 find 中返回正确的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 2020-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多