0

I am new to C++ and trying to create my first Octree structure.

Common way to store children is simply to store 8 pointers in each node.
like so:

class Octant
{
    Octant *child0;
    Octant *child1;
    Octant *child2;
    //...
}

This means each node will contain 8 pointers, witch is 64 bytes per node.
And also each leaf will store 8 null pointers.
To avoid memory wasting I want to store only one pointer to the first child
and allocate the array only during subdividing a leaf.

I tried this:

Octant *child[8]; // actually the same as 8 pointers + 1 pointer to an array
Octant child[8]; // One pointer but I have to allocate children in each Octant memory

so I did something like this:

class Octant
{
private:
    Octant *child; // Store only one pointer in each Octant

public:
    Octant();
    void subdivide();
    void doStuff(int i){ std::cout << i << " Child exists and do some stuff \n"; }
    //...
};
Octant::Octant() {

    child = nullptr; // leaves have no allocated children
    //...
}
void Octant::subdivide() {

    child = new Octant[8]; // I can allocate it wherever I want

    child[0].doStuff(0);
    child[1].doStuff(1);
    child[2].doStuff(2);
    child[3].doStuff(3);
    //...
}

It works fine, but there is a little problem during debugging.
My code "thinks" that the child is a pointer to one Octant not an array
For example if i do something like sizeof(child) it will return sizeof(pointer) (8 bytes)

So my question is it ok to use pointers like I did?
Or is there another "proper" way to do such stuff in C++?
Is there a way to convert a pointer to pointer[8] and does it make any sense?

  • I think you misunderstand how much memory is required for `Octant* child[8];`. You seem to imply that it will require at least 9 pointers' worth of memory, but in fact `&child` will be the same value as `&child[0]` because the address of an array is also the address of the first element in that array. Did you try looking at `sizeof(Octant)` for your different versions? – Nathan Pierson May 20 '22 at 15:37
  • 1
    *"My code "thinks" that the child is a pointer to one Octant not an array"*. Your code thinks right. `child` is in fact a pointer to `Octant`. Just see how you've declared it: `Octant *child`. – Jason May 20 '22 at 15:38
  • *and does it make any sense?* No, it doesn't make any sense to try. `sizeof` structure must be known at compile time and constant. You cannot change sizeof structure at runtime. – Yksisarvinen May 20 '22 at 15:49
  • @NathanPierson Hey thank you for answer. Yes I was wrong about "9 pointers". but anyway it still stores 8 pointers. Yes I tracked the sizeof(Octant) that is why I ended up with the last solution which gives the smallest sizeof(Octant) – Pasha Ho May 20 '22 at 15:49
  • @AnoopRana Thanks for reply. I know that I declared it myself, maybe my English is bad. The question was how to declare an "array pointer" without allocation but maybe it does not make any sense. I just did not find similar stuff, that is why I asking how to make it "right". – Pasha Ho May 20 '22 at 15:54
  • Mostly I'm just not sure what you're hoping to achieve. Reducing `sizeof(Octant)` from 8 `Octant*` pointers to 1 doesn't do that much for you if a valid `Octant` object is always supposed to have access to 8 pointers, just ones that live on the heap instead of right there in the object. You aren't actually using less memory, but you are making your copy constructor worse and your debugging less informative. – Nathan Pierson May 20 '22 at 15:59
  • @PashaHo If you want to create a pointer to an array(without dynamic allocation) you can do it as follows: `Octant arr[8]{}; Octant (*ptr)[8] = &arr ;`. I have explained this at the end of my answer. Check it out. Note here `ptr` points to the array and not to an `Octant` object. – Jason May 20 '22 at 16:13
  • @NathanPierson Yeah this problem is not very obvious but: assume we have a tree with depth = 2. Octant data is pointers to children only. **Total number of Octants** = root + 8 children + 64 leaves = **73**. In case it has 8 pointers: `sizeof(tree)` = `73 * 8 * sizeof(pointer)` In case it has 1 pointer: `sizeof(tree)` = `73 * sizeof(pointer)` And yes my problem is exactly weird blind debugging where I have to manually track children using pointer arithmetic. – Pasha Ho May 20 '22 at 16:53

1 Answers1

0

My code "thinks" that the child is a pointer to one Octant not an array..

Your code thinks right. child is in fact a pointer to Octant. Just see how you've declared it:

`Octant *child;`//this declared(and defines) child as a pointer to a non-const Octant object

The above defines an object named child which is a pointer to a non-const Octant object. Note that child has not been initialized in the above declaration. If you want to initailze it you could have just written:

Octant *child = nullptr; //uses in class initializer

Or

Even initialize it in the constructor initializer list :

//----------------vvvvvvvvvvvvvv----->use constructor initializer list to initialize child
Octant::Octant(): child(nullptr)
{
    
}

Now, the value of &child and &child[0] is the same.

Moreover, when you wrote:

child = new Octant[8]; //child points to the first element of the dynamically allocated array of size 8 

In the above assignment, you're assigning to child a pointer that points to the first element of the dynamically allocated array of size 8 and not 9.


The following is also possible:

//----------------vvvvvvvvvvvvvvvvvvvvvvv---->use constructor initializer list to initializer child
Octant::Octant(): child(new Octant[10]()) {

    
}

The question was how to declare an "array pointer" without allocation but maybe it does not make any sense.

Looking at your above quoted comment, it looks like you want to avoid dynamic allocation and declare a pointer to an array which can be done as shown below:

Octant arr[8]{}; //arr is an array of size 8 with elements of type Octant 
Octant (*ptr)[8] = &arr;//ptr is a pointer to an array of size 8 with elements of type Octant
Jason
  • 36,170
  • 5
  • 26
  • 60
  • Thank you for some insights. But `Octant arr[8]{} // allocates memory inside object (very bad for recursive)`, `Octant (*ptr)[8] = &arr // arr must exist before assignment.` What I want is something like this pseudo code: `Octant pointer child[8] = nullptr` and after some conditions allocate it `child = new Octant[8]` – Pasha Ho May 20 '22 at 17:06
  • @PashaHo You could use `std::vector` which is a dynamic collection and you can add elements at a later time when you need. For example, `std::vector arr; //this creates an empty vector`, then when you need you can add elements to it either using `push_back`/`emplace_back` or resizing it using `std::vector::resize`. See [demo1](https://onlinegdb.com/KFWSfgVTM) and [demo2](https://onlinegdb.com/XnoL77Pcp). – Jason May 20 '22 at 17:16