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