2009-11-20 81 views
2

我有以下类似四叉树的结构,其中每个单元可以是内部节点或叶。 如果它是一片叶子,它可以存储一种颜色。 如果它是一个内部节点,它存储的指针到四个孩子(其可以是叶或内节点):quadTree与union的问题

class RenderBucketCell{ 
public: 
    RenderBucketCell(); 
    RenderBucketCell(float R, float G, float B, float A, unsigned short X, unsigned short Y); 
    ~RenderBucketCell(); 

    void split(); 

    void collapse(); 

    bool isLeaf; 
    RenderBucketCell* neighbours[8]; 
    unsigned short x; 
    unsigned short y; 
    union{ 
     struct{ 
      float r; 
      float g; 
      float b; 
      float a; 
     }; 
     struct{ 
      RenderBucketCell* children[4]; 
     }; 
    }; 
}; 

如果单元是内节点,那么它不需要存储颜色。如果它是一片叶子,那么它不需要存储指向儿童的指针。因此,颜色和孩子应该共享相同的内存(联合)

有一个函数split()将一个叶转换为一个内部节点,并为当前单元具有的相同颜色的子元素(叶子)创建片刻:

void RenderBucketCell::split(){ 
isLeaf=false; 
float rt = r;//make backups of the values before setting the children (union) 
float gt = g; 
float bt = b; 
float at = a; 
unsigned short xt2 = x*2; 
unsigned short yt2 = y*2; 
children[0] = new RenderBucketCell(rt,gt,bt,at, xt2, yt2); 
children[1] = new RenderBucketCell(rt,gt,bt,at, xt2+1, yt2); 
children[2] = new RenderBucketCell(rt,gt,bt,at, xt2, yt2+1); 
children[3] = new RenderBucketCell(rt,gt,bt,at, xt2+1, yt2+1); 
} 

现在我正在调试split()函数。我所以现在在该行

children[0] = new RenderBucketCell(rt,gt,bt,at, xt2, yt2); 

调试点: 调试器停在这条线,我观察membervalues。我做了一个程序步,这样该行被执行(指令光标现在在下一行)。行被执行后,children [0]的pointervalue仍然是一样的!相反,儿童[2]的指针值已经改变(与浮点值b一起)

有人可以解释我这种行为吗?我究竟做错了什么?

谢谢!

+0

有没有可能'RenderBucketCell'构造函数可能调用'split()'? (我认为不是,但最好检查一下。) – dave4420 2009-11-20 16:57:37

+0

哎Dave no - 构造函数只是为字段r,g,b,a,isLeaf,neighbors设置默认值[8],x和y – Mat 2009-11-20 17:14:42

+0

此时,它是值得问一下你使用的编译器和调试器,因为你的代码看起来不错。 Split()是否在与RenderBucketCell的其余部分分开的文件中实现?它似乎使用不同的整数/指针大小或对齐方式。 – Joh 2009-12-06 11:16:27

回答

0

这很可能是使用联合的问题。 children [2]是编译器给union的第一个未分配的内存位置(假设有4个字节的浮点数和8个字节的指针)。我不确定为什么会发生这种情况,但是像这样的问题是工会不是可取的结构的主要原因之一。

0

我通过给节点四个unsigned long来解决你的问题(一个节点可以有指针或数据)。当节点是一个子节点时,那些无符号的long被转换为浮点数。当它是父节点时,它们存储子节点的地址。

但是,您必须绝对确定要使用此优化,因为它成为调试的噩梦。

0

儿童[0]的值是相同的并不令人意外,因为每次运行程序时内存可能会以非常相似的方式进行分区,即儿童内存中的值[0]仍然会在上一次运行中出现,“新操作员”很可能只是检索上次使用的内存。这是我对那里发生的事情的猜测。

至于儿童[2],我不完全确定。我能想到的唯一的东西就是构造函数。

1

您正在使用可以在联合中称为“匿名结构”的东西。我不相信这些是C++标准的一部分,尽管我读过一些编译器支持它们。在任何情况下,我会留下清晰的这些和使用以下命令:

union{ 
     struct { 
       float r; 
       float g; 
       float b; 
       float a; 
     } color; 
     struct { 
       RenderBucketCell* children[4]; 
     } subnode; 
}; 

您的代码将是稍微详细,你必须参考renderBucketCell.color.r而不是renderBucketCell.r,但它可以解决您的问题。