【问题标题】:vector of reference wrapper, push_back failure?参考包装向量,push_back 失败?
【发布时间】:2017-07-24 08:47:58
【问题描述】:

我有一个给我带来麻烦的问题;我的目标是创建一个八叉树。

实际上,它非常便宜(但对于我想要用那个八叉树做的事情来说已经足够了)。

我的问题是我的std::vector<std::reference_wrapper<Point>> 填充了相同的值。所以我的插入创建了一个无限循环。 但这是代码,也许它会更容易理解。我在出现错误的地方添加了注释。

source.cpp

void main(){
    std::random_device rd;
    std::mt19937 rng(rd());
    std::uniform_real_distribution<double> uni(0, 2);
    auto random_integer = uni(rng);
    Point firstCenter = Point(1, 1, 1);
    Point firstHalfDimension = Point(1, 1, 1);
    Octree oct(firstCenter, firstHalfDimension);

    for (int i = 0; i < 3; ++i) {
        double x = uni(rng);
        double y = uni(rng);
        double z = uni(rng);
        Point ptmp = Point(x, y, z);
        std::cout << x << " " << y << " " << z << std::endl;
        auto po = std::ref(ptmp);
        oct.insert(po);
    }
}

八叉树.hpp

class Octree {
    Node octree;
    Point firstCenter;
    Point firstHalfDimension;

public: 
    Octree() = default;
    Octree( Point& firstCenter, Point& firstHalfDimension) :
        firstCenter(firstCenter), firstHalfDimension(firstHalfDimension), octree(firstCenter, firstHalfDimension) {}

    void insert(std::reference_wrapper<Point> pt) {
        octree.insert(pt);
    }
};

Node.hpp(出现问题的地方)

#define MAXVAL 2
using Point = gmtl::Vec3d;

class Node {
    Point center;
    Point halfDimension;
    std::vector<std::reference_wrapper<Point>> datas;
    std::array<std::shared_ptr<Node>, 8> children;


    int getOctant(const std::reference_wrapper<Point> p) {
        int oct = 0;
        if (p.get()[0] >= center[0]) oct |= 4;
        if (p.get()[1] >= center[1]) oct |= 2;
        if (p.get()[2] >= center[2]) oct |= 1;
        return oct;
    }

    const bool isLeaf()  {
        return !children[0];
    }

public:

    Node(Point center, Point halfDimension) : center(center), halfDimension(halfDimension){
    }
    void insert(const std::reference_wrapper<Point> p) {
        if (isLeaf()){
            if (datas.size() == MAXVAL) { //Must subdivide
                std::cout << p.get()[0] << " " << p.get()[1] << " " << p.get()[2] << std::endl;
                for (int i = 0; i < datas.size(); ++i) {
                    std::cout << datas[i].get()[0] << " "
                        << datas[i].get()[1] << " "
                        << datas[i].get()[2] << std::endl;
 //The problem is here : the vector is filled with the same values, and it's the same value as p. let's say p = (0.4,0.7,0.8), then the for loop will show to the screen : 
 // 0.4 0.7 0.8
 // 0.4 0.7 0.8
 // 0.4 0.7 0.8
                }
                for (int i = 0; i < 8; ++i) {
                    Point newCenter;
                    newCenter[0] += halfDimension[0] * (i & 4 ? .5f : -.5f);
                    newCenter[1] += halfDimension[1] * (i & 2 ? .5f : -.5f);
                    newCenter[2] += halfDimension[2] * (i & 1 ? .5f : -.5f);
                    children[i] = std::make_shared<Node>(newCenter, halfDimension * .5);
                }
                int octant = getOctant(p);
                children[octant]->insert(p);
                for (int i = 0; i < datas.size(); ++i) {
                    int octant = getOctant(datas[i]);
                    children[octant]->insert(datas[i]);
                }


            }
            else { //Just add
                datas.push_back(p);
            }
        }
        else { //Non-leaf node
            children[getOctant(p)]->insert(p);
        }
    }
};

我真的不明白我做错了什么。

【问题讨论】:

  • 您正在存储对ptmp 变量的引用,该变量超出范围并在循环的每次迭代中被破坏。 为什么你想要一个引用向量?应该解决的问题是什么?为什么你可以使用 Point objects 的向量来代替?
  • 如果您满足以下条件,您将更快地获得帮助:1. 将代码减少到演示问题所需的最少行数 2. 发布实际错误消息
  • 即使您使ptmp 对象具有更长的生命周期,所有引用仍将引用一个 ptmp 对象。 并且请记住,std::reference_wrapper 对象本身会占用一些空间,任何对象都不能有零大小。在尝试优化之前,请编写尽可能简单直接的代码。然后如果(并且仅当)“性能”不够好(通常足够好)然后你测量并看看你可以做优化。
  • 是的!我明白了...我在这里删除了reference_wrapper,并仅尝试使用Points。现在我知道我有同样的问题(无限递归),但这不是由于 reference_wrapper。
  • 引用必须引用某些东西。那件事仍然需要记忆。为了引用数十亿个点,您仍然必须在某个地方拥有数十亿个点,即使它们实际上不在这个向量中。

标签: c++ vector octree reference-wrapper


【解决方案1】:
std::vector<std::reference_wrapper<Point>> datas;

某物必须拥有该向量所包含的对象。

您在向量中填充了对不再存在的对象的引用。目前尚不清楚为什么您认为需要引用向量,但除非您很好地解释了为什么正常方式(值向量)不适合您,否则您不应该做一些不寻常的事情。

【讨论】:

  • 你是对的。其实我相信我不需要这个向量。我以为它会节省空间,但没有。我误解了什么是真正的参考包装。我只需要用值填充我的向量,当涉及到创建孩子时,我会填满我的孩子并清空母亲的向量,这样它就不会无用地发生。
猜你喜欢
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 2013-03-28
  • 2012-03-25
  • 1970-01-01
  • 2021-06-23
  • 2020-11-20
  • 1970-01-01
相关资源
最近更新 更多