Pointers in C++, please help

Discussion of chess software programming and technical issues.

Moderators: bob, hgm, Harvey Williamson

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
Michael Sherwin
Posts: 3046
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Pointers in C++, please help

Post by Michael Sherwin » Sat Apr 20, 2019 6:58 pm

I've spent hours in my C++ primer and other books and online with no success.

I want to use a pointer to a two dimensional array like it was an array name. This code works and I am okay with that but it uses pure pointer arithmetic, however, for readability I want to use the pointer like array notation instead.

Code: Select all

unsigned char *mvsQ[] = { &mvsNW[0][0], &mvsNE[0][0], &mvsSW[0][0], &mvsSE[0][0],
                          &mvsNN[0][0], &mvsEE[0][0], &mvsSS[0][0], &mvsSW[0][0] };

Code: Select all

void WSBBG(threadS *t, u08 id, u08 fs, u08 *inv, u64 *bb) {
  u08 i;
  u64 ray;

  do {
    i = FirstBit32(*inv);
    *inv ^= (1 << i);
    switch (i) {
    ...
   case NN:
      ray = (rayNN[fs] & belowInc[FirstBit64(rayNN[fs] & t->aPieces)] & ~t->wPieces);
      *bb &= andNN[fs];
       *bb |= ray; mvsNN[fs][0] = (u08)__popcnt64(ray);
      break;
  ...
      mvs = mvsQ[i];
    while (ray) {
      n++;
      ts = FirstBit64(ray);
      ray ^= one << ts;
      *(mvs + (((fs << 3) + n))) = ts; // I want to do something like,  mvs[fs][n] = ts;
    }
     *(mvs + (fs << 3)) = n;
    t->inv[t->brd[fs]][t->top[t->brd[fs]]] = 0;
  } while (*inv);
}
         
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

Ras
Posts: 1162
Joined: Tue Aug 30, 2016 6:19 pm
Contact:

Re: Pointers in C++, please help

Post by Ras » Sat Apr 20, 2019 7:08 pm

If you have this:

Code: Select all

*(mvs + (((fs << 3) + n))) = ts; // I want to do something like,  mvs[fs][n] = ts;
then the shift suggests that the n variable stretches over 3 bit, i.e. it can go from 0 to 7. That means a lower array dimenion of 8. Assuming that the other dimension is also 8 because it is about a chessboard:

Code: Select all

TYPE_T mvs[8][8];
mvs[fs][n] = ts;
...
mvs[fs][0] = n; /*use a proper constant/define for 0 to avoid the magic number 0 here!*/
However, this would be idiomatic C code. In modern C++, dealing with raw pointers is usually regarded as bad practice.
Rasmus Althoff
https://www.ct800.net

Michael Sherwin
Posts: 3046
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Sat Apr 20, 2019 7:20 pm

Ras wrote:
Sat Apr 20, 2019 7:08 pm
If you have this:

Code: Select all

*(mvs + (((fs << 3) + n))) = ts; // I want to do something like,  mvs[fs][n] = ts;
then the shift suggests that the n variable stretches over 3 bit, i.e. it can go from 0 to 7. That means a lower array dimenion of 8. Assuming that the other dimension is also 8 because it is about a chessboard:

Code: Select all

TYPE_T mvs[8][8];
mvs[fs][n] = ts;
...
mvs[fs][0] = n; /*use a proper constant/define for 0 to avoid the magic number 0 here!*/
However, this would be idiomatic C code. In modern C++, dealing with raw pointers is usually regarded as bad practice.
Hi Ras, Thanks! How would it be done with good practice in C++? I have no clue.
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

Ras
Posts: 1162
Joined: Tue Aug 30, 2016 6:19 pm
Contact:

Re: Pointers in C++, please help

Post by Ras » Sat Apr 20, 2019 7:43 pm

Michael Sherwin wrote:
Sat Apr 20, 2019 7:20 pm
Hi Ras, Thanks! How would it be done with good practice in C++? I have no clue.
You'd use some of the STL provided types. You could use either a std::vector inside another std::vector, or std::array inside another std::array. I think the latter will be faster here because the dimensions are fixed so that the flexibility of std::vector is not needed here.

Code: Select all

std::array<std::array<int, 3>, 2> my_matrix {{
    {{0, 1, 2}},
    {{3, 4, 5}}
 }};

my_matrix[1][2] = 42;
However, you should benchmark whether that is slower than directly using pointers.
Rasmus Althoff
https://www.ct800.net

Michael Sherwin
Posts: 3046
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Sat Apr 20, 2019 7:57 pm

Ras wrote:
Sat Apr 20, 2019 7:43 pm
Michael Sherwin wrote:
Sat Apr 20, 2019 7:20 pm
Hi Ras, Thanks! How would it be done with good practice in C++? I have no clue.
You'd use some of the STL provided types. You could use either a std::vector inside another std::vector, or std::array inside another std::array. I think the latter will be faster here because the dimensions are fixed so that the flexibility of std::vector is not needed here.

Code: Select all

std::array<std::array<int, 3>, 2> my_matrix {{
    {{0, 1, 2}},
    {{3, 4, 5}}
 }};

my_matrix[1][1] = 42;
However, you should benchmark whether that is slower than directly using pointers.
Thanks again! If I can understand it I'll give it a try. I have the, C++ Programming Language, by Bjarne Stroustrup. Maybe std::array will be in there. :D
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

odomobo
Posts: 59
Joined: Thu Jul 05, 2018 11:09 pm
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo » Tue Apr 30, 2019 4:04 pm

BTW, std::array should have the same performance as a normal array. The purpose of having std::array in the language (as I understand it) is providing a strong type to represent an array (i.e. it won't decay to a pointer) and provides additional features (i.e. runtime bounds checking with .at() ). Otherwise, it should provide 0 runtime overhead over a normal array, as it should compile down to the same machine code (as long as you use index operator [] instead of .at() ). Of course, the compiler won't necessarily do as it's supposed to, so benchmarking is king

Michael Sherwin
Posts: 3046
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Tue Apr 30, 2019 5:45 pm

odomobo wrote:
Tue Apr 30, 2019 4:04 pm
BTW, std::array should have the same performance as a normal array. The purpose of having std::array in the language (as I understand it) is providing a strong type to represent an array (i.e. it won't decay to a pointer) and provides additional features (i.e. runtime bounds checking with .at() ). Otherwise, it should provide 0 runtime overhead over a normal array, as it should compile down to the same machine code (as long as you use index operator [] instead of .at() ). Of course, the compiler won't necessarily do as it's supposed to, so benchmarking is king
I looked into std::array. " it won't decay to a pointer" As best I can tell is this means that even when passing a standard array by reference the compiler is smart enough to allow array notation rather than having to use pointer arithmetic. That is just a guess because it really did not say that explicitly. So concerning my original question, how do I use std::array to load a pointer from an array of pointers and then use that pointer as it were an array name? I do not see the connection.
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

odomobo
Posts: 59
Joined: Thu Jul 05, 2018 11:09 pm
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo » Tue Apr 30, 2019 6:04 pm

Can you post the declaration for mvsNW? Then I can walk you through it. it shouldn't require std::array to get this to work the way you want.

Decaying to a pointer doesn't actually affect you right now, but I can show you an example:

Code: Select all

void foo()
{
    int arr[10];
    // ...
    bar(arr); // this works; int array arr decays to an int pointer
    
    std::array<int, 10> arr2;
    // ...
    bar(arr2); // compile-time error
}

void bar(int *arr)
{
    // ...
}

Michael Sherwin
Posts: 3046
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Tue Apr 30, 2019 6:30 pm

odomobo wrote:
Tue Apr 30, 2019 6:04 pm
Can you post the declaration for mvsNW? Then I can walk you through it. it shouldn't require std::array to get this to work the way you want.

Decaying to a pointer doesn't actually affect you right now, but I can show you an example:

Code: Select all

void foo()
{
    int arr[10];
    // ...
    bar(arr); // this works; int array arr decays to an int pointer
    
    std::array<int, 10> arr2;
    // ...
    bar(arr2); // compile-time error
}

void bar(int *arr)
{
    // ...
}

Code: Select all

// These are vectors for the bishop. Ex: mvsNW[A1][0] is the number of squares. [A1][1-7] are the to squares.
u08 mvsNW[64][8];
u08 mvsNE[64][8];
u08 mvsSE[64][8];
u08 mvsSW[64][8];

// This is an array of pointers to the above arrays.
unsigned char *mvsB[] = { &mvsNW[0][0], &mvsNE[0][0], &mvsSW[0][0], &mvsSE[0][0] };

// In this code I declare unsigned char *ptr and in line 4 it is assigned each array address by a for loop
// Then It is used with pointer arithmetic. But, I thought it would be possible to use it as an array name as in ptr[fs][j]
void WBf(threadS *t, u08 id, u08 depth, moveS *m) {
  unsigned char *ptr = &t->inv[id][t->top[id]];  m->fs = t->sqr[id];
  if (*ptr) WSBBG(t, id, m->fs, ptr, &t->stk[id][t->top[id]]);
  for (u08 i = 0; i < 4; i++) { ptr = mvsB[i];
    for (u08 j = 1; j <= *(ptr + (m->fs << 3)); j++) {
      m->ts = *(ptr + ((m->fs << 3) + j));
      m->id = t->brd[m->ts];
      m->typ = (m->id) ? WBC : WBM;
      MakeMove(t, m);
      if (depth > 0) Perft(t, depth - 1);
      TakeBack(t, m);
    }
  }
}

I hate if statements. Pawns demand if statements. Therefore I hate pawns.

odomobo
Posts: 59
Joined: Thu Jul 05, 2018 11:09 pm
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo » Tue Apr 30, 2019 7:01 pm

Actually, something I just realized is that c++ doesn't like the notation for pointers to normal arrays, so std::array will help us out here. Maybe there's a way to do it, but if so it's beyond me.

Code: Select all

// These are vectors for the bishop. Ex: mvsNW[A1][0] is the number of squares. [A1][1-7] are the to squares.
// Note that we have to declare the dimensions in reverse order, since we're explicitly nesting the types
std::array<std::array<u08, 8>, 64> mvsNW;
std::array<std::array<u08, 8>, 64> mvsNE;
std::array<std::array<u08, 8>, 64> mvsSE;
std::array<std::array<u08, 8>, 64> mvsSW;

// This is an array of pointers to the above arrays.
// Note that this is storing the exact same pointer as befores, but now it's preserving type information.
// We could have mvsB itself be a std::array, but it's not necessary.
std::array<std::array<u08, 8>, 64> * mvsB[] = { &mvsNW, &mvsNE, &mvsSW, &mvsSE };

// In this code I declare unsigned char *ptr and in line 4 it is assigned each array address by a for loop
// Then It is used with pointer arithmetic. But, I thought it would be possible to use it as an array name as in ptr[fs][j]
void WBf(threadS *t, u08 id, u08 depth, moveS *m) {
  unsigned char *ptr = &t->inv[id][t->top[id]];  m->fs = t->sqr[id];
  if (*ptr) WSBBG(t, id, m->fs, ptr, &t->stk[id][t->top[id]]);
  for (u08 i = 0; i < 4; i++) { 
    // Why are we dereferencing, and then holding a reference to the underlying array object? Why not leave it as a pointer?
    // Because otherwise we'd need to explicitly deference like this:
    // (*mvs)[m->fs][j]
    // BTW, if we just dereferenced, but didn't hold a reference, semantically we're asking the compiler to copy the contents of the array onto the stack.
    auto & mvs = *mvsB[i];
    for (u08 j = 1; j <= mvs[m->fs][0]; j++) {
      m->ts = mvs[m->fs][j];
      m->id = t->brd[m->ts];
      m->typ = (m->id) ? WBC : WBM;
      MakeMove(t, m);
      if (depth > 0) Perft(t, depth - 1);
      TakeBack(t, m);
    }
  }
}
Let me know if you have any questions

Post Reply