Starting a new project - Rommie

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Starting a new project - Rommie

Post by mvanthoor »

Mike Sherwin wrote: Thu Mar 03, 2022 7:10 pm If I understand new correctly I could write

int* intArray = new int[10];
Last time I used C++ is too long gone to be sure, but I suspect you could. Why would you want to do that though? An array already is a pointer. If you create an array of 10 ints, the variable effectively is a pointer to the first int in that array. If "new" gives you a pointer to that array variable, then you'd have a pointer to a pointer.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Starting a new project - Rommie

Post by Mike Sherwin »

mvanthoor wrote: Thu Mar 03, 2022 7:25 pm
Mike Sherwin wrote: Thu Mar 03, 2022 7:10 pm If I understand new correctly I could write

int* intArray = new int[10];
Last time I used C++ is too long gone to be sure, but I suspect you could. Why would you want to do that though? An array already is a pointer. If you create an array of 10 ints, the variable effectively is a pointer to the first int in that array. If "new" gives you a pointer to that array variable, then you'd have a pointer to a pointer.
Because for a multithreaded chess engine the number of available threads is not known ahead of time. I could initially declare maxThreads = 1024; or some other high number then declare Thread* thread = new Thread[maxThreads]; but that seems noobish. And my intuition tells me it is not correct. I still think that an additional level of indirection is also needed in the call to new itself. I looked on the www but most answers and tutorials didn't really cover what I want to do or just gave incorrect answers. I'll look again and get back! Thanks :D
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Starting a new project - Rommie

Post by Mike Sherwin »

So I'm thinking this may be correct.

Thread** thread;
Thread* t;

thread = new Thread*[maxThreads];
t = thread[0];

Anyone?
:?:
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Starting a new project - Rommie

Post by mvanthoor »

Personally, I'd just do this with like this:

Code: Select all

int nr_of_threads = read_this_from_cmd_line();

Thread *threads = (Thread *) malloc(nr_of_threads)
"threads" is a variable of "pointer to Thread", which points to the first element in a memory block. You should be able to address this as an array with threads[0].

(Or you must be hell-bent in doing it the C++ way.)
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
Mergi
Posts: 127
Joined: Sat Aug 21, 2021 9:55 pm
Full name: Jen

Re: Starting a new project - Rommie

Post by Mergi »

Mike Sherwin wrote: Thu Mar 03, 2022 8:37 pm So I'm thinking this may be correct.

Thread** thread;
Thread* t;

thread = new Thread*[maxThreads];
t = thread[0];

Anyone?
:?:
C style raw pointers, memory allocations and arrays should stay in C - in my opinion if one is making a C++ engine, they ought to be using C++. 8-)
C++ way would be to create a std::vector of threads ... or rather a vector of smart (shared/unique) pointers to threads and not worry about memory and pointers.

Code: Select all

std::vector<std::unique_ptr<Thread>> threads;
for (auto i = 0; i < maxThreads; ++i) {
	threads.emplace_back(new Thread());
}

// accessed either via
threads[0]
// or
threads.at(0) // this does boundry checking, so slightly slower but that should be irrelevant for the threads vector

// calling methods/accessing member variables is just like with raw pointers
threads.at(2)->CallingSomeMethod(arg1, arg2);
threads.at(2)->somePublicVariable;
And releasing the allocated memory and changing the amount of threads becomes as simple as:

Code: Select all

threads.clear();
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Starting a new project - Rommie

Post by Mike Sherwin »

Mergi wrote: Thu Mar 03, 2022 11:17 pm
Mike Sherwin wrote: Thu Mar 03, 2022 8:37 pm So I'm thinking this may be correct.

Thread** thread;
Thread* t;

thread = new Thread*[maxThreads];
t = thread[0];

Anyone?
:?:
C style raw pointers, memory allocations and arrays should stay in C - in my opinion if one is making a C++ engine, they ought to be using C++. 8-)
C++ way would be to create a std::vector of threads ... or rather a vector of smart (shared/unique) pointers to threads and not worry about memory and pointers.

Code: Select all

std::vector<std::unique_ptr<Thread>> threads;
for (auto i = 0; i < maxThreads; ++i) {
	threads.emplace_back(new Thread());
}

// accessed either via
threads[0]
// or
threads.at(0) // this does boundry checking, so slightly slower but that should be irrelevant for the threads vector

// calling methods/accessing member variables is just like with raw pointers
threads.at(2)->CallingSomeMethod(arg1, arg2);
threads.at(2)->somePublicVariable;
And releasing the allocated memory and changing the amount of threads becomes as simple as:

Code: Select all

threads.clear();
I'm old and I was born with a short term memory disability that gets worse with age. It takes me forever to learn something new. However this does not seem overly difficult. So let me see if I can understand.


This creates basically an undefined length array (okay a vector) for pointers? It is also a class with built in methods and data?
std::vector<std::unique_ptr<Thread>> threads;

threads.emplace_back(new Thread()); is one of the built in methods that somehow does not need i. It must just grow the vector and it knows Thread is a structure. Or do I have to make a Thread class?
for (auto i = 0; i < maxThreads; ++i) {
threads.emplace_back(new Thread());
}
I am a self taught C programmer that simply uses C++ as a better C. The learning curve is not so implacable and seems to be easier than straight C in some ways. I have a C++ primer from 20+- years ago. My engine RomiChess was originally written using Turbo C 1.0. I won't live long enough to learn classes. I tried about 10/15 or so years ago and could not keep any of it in memory long enough and I got nowhere with it. Your advice might be fine for a young person with a good memory. For me though, well it is just not for me. I will totally forget your code example as soon as I close this thread. RomiChess uses "raw" pointers extensively and I've had relatively no trouble with them as long as I had my C primer in one hand while I wrote it. RomiChess would not even run in the Turbo C debugger (did Turbo C even have a debugger?) or later in the MSVC 2005 (or was it MSVC 6.0?) debugger. So I wrote RomiChess without even using a debugger. lol The bottom line is I'm better off sticking with what I know. The problem I need help with is creating a dynamic array of pointers because that is new for me. So does my better C dynamically created pointers work or not? But I do appreciate your example code. I'll make a note of it and try to implement it. Thanks!
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Starting a new project - Rommie

Post by Mike Sherwin »

mvanthoor wrote: Thu Mar 03, 2022 10:54 pm Personally, I'd just do this with like this:

Code: Select all

int nr_of_threads = read_this_from_cmd_line();

Thread *threads = (Thread *) malloc(nr_of_threads)
"threads" is a variable of "pointer to Thread", which points to the first element in a memory block. You should be able to address this as an array with threads[0].

(Or you must be hell-bent in doing it the C++ way.)
Thanks that looks familiar. I kind of like new but using malloc makes perfect sense with no guessing on my part needed. Only one question though. I see that malloc creates a dynamic array of pointers but does it also set aside memory for nr_of_threads or does that need another step. And does new also need another step? My brain is shutting down so I should take a break.
Mergi
Posts: 127
Joined: Sat Aug 21, 2021 9:55 pm
Full name: Jen

Re: Starting a new project - Rommie

Post by Mergi »

Your code does create a dynamic array of pointers to the thread objects. You never construct the threads themselves though, just the pointers. I dont believe that's what you want ... i feel like you are overthinking it with the pointers to pointers.

Something like this would work though.

Code: Select all

    Thread* threads = new Thread[maxThreads];  // we have a dynamic array of threads that are default constructed
    Thread* t = &thread[0]; // now t points to the first thread    
    
    // it is equivalent to the malloc C code
    Thread *threads = (Thread *) malloc(maxThreads * sizeof(Thread))
Yes, a vector is a very easy to use resizable array with a couple handy methods 8-)
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Starting a new project - Rommie

Post by Mike Sherwin »

I just came up with this before seeing your reply.

Code: Select all

thread = new Thread*[maxThreads];

  for (s32 i = 0; i < maxThreads; i++) {
	thread[i] = new Thread;
  }

  t = thread[0];
This looks logically correct to me. :?:

EDIT: I want to program in the KISS language compiler. Would someone hurry up and write it? 8-)
:lol:
Last edited by Mike Sherwin on Fri Mar 04, 2022 2:22 am, edited 1 time in total.
Mergi
Posts: 127
Joined: Sat Aug 21, 2021 9:55 pm
Full name: Jen

Re: Starting a new project - Rommie

Post by Mergi »

Mike Sherwin wrote: Fri Mar 04, 2022 1:59 am I just came up with this before seeing your reply.

Code: Select all

thread = new Thread*[maxThreads];

  for (s32 i = 0; i < maxThreads; i++) {
	thread[i] = new Thread;
  }

  t = thread[0];
This looks logically correct to me. :?:
Yea, this seems correct. But i'd still suggest getting rid of the extra indirection ... why do you need it? It will only make deallocation and memory management harder later on.