【问题标题】:Why are pointers slower in this case [closed]为什么在这种情况下指针变慢[关闭]
【发布时间】:2013-09-02 14:47:32
【问题描述】:

我正在实现一个四叉树。我重新实现了我的第一稿(完整版本可以看到here),它使用了智能指针和使用原始指针的版本的引用。

但是填充新树显然要慢两倍,为什么会这样?

旧版本代码:

// returns if coordinates fit in the tree
const bool contains(const double &x, const double &y, const double &w, const double &h) const {
    return (this->x < x &&
            this->y < y &&
            this->x + this->w > x + w &&
            this->y + this->h > x + h);
}
// returns if an element fits in the tree
const bool contains(const std::shared_ptr<Rectangle> &rect) const {
    return contains(rect->getX(), rect->getY(), rect->getW(), rect->getH());
}

// inserts an element in the tree
const bool insert(const std::shared_ptr<Rectangle> &rect) {
    // if rect is too big for this quadtree
    if(!contains(rect)) {
        auto sp = getParent();
        if(sp == nullptr) {
            return false;
        }
        return sp->insert(rect);
    }
    // if element theoretically fits in subtree
    else if(rect->getW() < getW() / 2 && rect->getH() < getH() / 2) {
        if(!subtrees[0]) {
            generateSubtrees();
        }
        for(const auto &subtree: subtrees) {
            if(subtree->contains(rect)) {
                return subtree->insert(rect);
            }
        }
    }
    children.insert(children.end(), rect);
    return true;
}

void generateSubtrees() {
    subtrees[0] = std::make_shared<QuadTree>(getW() / 2.0f, getH() / 2.0f, getX(),                 getY(),                 this);
    subtrees[1] = std::make_shared<QuadTree>(getW() / 2.0f, getH() / 2.0f, getX() + getW() / 2.0f, getY(),                 this);
    subtrees[2] = std::make_shared<QuadTree>(getW() / 2.0f, getH() / 2.0f, getX(),                 getY() + getH() / 2.0f, this);
    subtrees[3] = std::make_shared<QuadTree>(getW() / 2.0f, getH() / 2.0f, getX() + getW() / 2.0f, getY() + getH() / 2.0f, this);

}

用这个版本填充树的时间是大约。 0.001367 秒为 1000 元素。

然后我重新实现了这个功能:

// Returns if a Rectangle fits in the tree
const bool contains(const Rectangle *rect) const {
    return (this->x < rect->x &&
            this->y < rect->y &&
            this->x + this->w > rect->x + rect->w &&
            this->y + this->h > rect->y + rect->h);
}

// Inserts an element in the tree
const bool insert(Rectangle *rect) {
    if(!contains(rect) && parent == nullptr) {
        return false;
    }
    if(rect->w < this->w / 2.0f && rect->w < this->w / 2.0f) {
        if(children[0]==nullptr){
            generateSubtrees();
        }
        for(const auto child: children) {
            if(child->contains(rect)) {
                return child->insert(rect);
            }
        }
    }
    elements.push_back(rect);
    return true;
}

// Generate the subtrees
void generateSubtrees() {
    children[0] = new Quadtree(w/2.0f, h/2.0f, x,        y,        this);
    children[1] = new Quadtree(w/2.0f, h/2.0f, x+w/2.0f, y,        this);
    children[2] = new Quadtree(w/2.0f, h/2.0f, x,        y+w/2.0f, this);
    children[3] = new Quadtree(w/2.0f, h/2.0f, x+w/2.0f, y+w/2.0f, this);
}

1000 元素填充这个版本的时间大约需要。 0.00312 秒。

如您所见,使用指针的第二个版本要慢得多。

PS:我用

循环填充旧树(版本 1)

insert(std::make_shared&lt;Rectangle&gt;(std::rand()%999, std::rand()%999, 1, 1))

和新的(版本 2)

insert(new Quadtree::Rectangle(std::rand()%999, std::rand()%999, 1, 1))

你能告诉我性能损失的原因在哪里吗?

(查看 cmets 了解更多信息)

【问题讨论】:

  • “慢得多”要慢多少?您是否在启用优化的情况下进行编译?
  • OP 声明:0.00312s 与 0.00137s。就个人而言,我会非常谨慎地基于这么小的数字做任何事情,但我不是优化专家。
  • 引用被实现为指针,因此完全没有理由期望任何性能差异。 您是否启用了编译器优化?
  • 两个版本之间有很多不同之处,不仅仅是智能指针。例如,在第一个版本中,insert 函数在第一个if 中调用sp-&gt;insert,而第二个版本只是返回。这只是一个例子。我投票结束,因为没有办法回答这个问题,任何这些差异都可能导致性能变化。
  • @Walter 你能给我一个提示或显示一些代码吗?

标签: c++ pointers c++11 tree quadtree


【解决方案1】:

这段代码

const bool contains(const double &x, const double &y, const double &w, const double &h) const {
    return (this->x < x &&
            this->y < y &&
            this->x + this->w > x + w &&
            this->y + this->h > x + h);  <---- error here
}

和这段代码不一样

const bool contains(const Rectangle *rect) const {
    return (this->x < rect->x &&
            this->y < rect->y &&
            this->x + this->w > rect->x + rect->w &&
            this->y + this->h > rect->y + rect->h);
}

第一个写错x + h,应该写成y + h

【讨论】:

  • 这很荒谬,但这确实改变了很多。修正后10000000的时间填旧版本提高到16秒以上,而新版本低于10秒。
【解决方案2】:

您需要更大的测试数据才能获得可靠的陈述。

您还希望将“时间混乱”倍增。

之后,您可能会使用 Profiler 来确定您的根本原因是什么。

这可能是您的 cpu 缓存问题(结构更改)或您现在正在执行的较慢的操作。

【讨论】:

  • 我在上面的 cmets 中添加了更大的数字。此外,时间测量已经进行了多次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
相关资源
最近更新 更多