well, I'm doing the log2 manuallysje wrote:I have found it handy to use the log2 of the entry count when dealing with transposition table allocation and indexing issues. Separate inline functions with the log2 entry count as a formal parameter are used for entry count determination, address mask determination, total table size determination, etc. Other routines use a log2 entry count formal for allocation. I also have four different transposition table types plus the perft table, so the log2 entry count functions are used in several places.lucasart wrote:Thank you all for your useful comments. Here is my code for allocating (or resizing) the hash table. I put lots of comments, because all this was not obvious for me
Let me know if you see anything that doesn't make sense.
malloc out of memory
Moderator: Ras
-
lucasart
- Posts: 3243
- Joined: Mon May 31, 2010 1:29 pm
- Full name: lucasart
Re: malloc out of memory
-
Sven
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: C++ new()
That was not what I meant, sorry for not expressing it unambiguously. What I meant was, if you compile without exception handling then the compiler might also arrange to present the "nothrow" variant of operator new to you as the default, without explicitly having to call new(nothrow) (i.e. with nothrow as default parameter). I'm not sure whether this actually happens but I could imagine this would make sense, since the other way round, calling an "operator new" that throws an exception which is never handled due to disabling exception handling via compiler switch, is somehow inconsistent.sje wrote:It would be dangerous to assume that the plain new() would do anything other than what the standard says regardless of the presence of exception handling.Sven Schüle wrote:But if you compile without exception handling, don't you get the nothrow version of operator new offered by default, since the other versions are not available?sje wrote:In C++, only the special nothrow version of new() can return a zero value. The plain new() should never return a zero, either with or without exception handling.Sven Schüle wrote:1) If you use C++ with exceptions (usually not in a chess program) then use the "new" operator and deal with exceptions at an appropriate point. You can safely assume that the return value of "new" is non-zero (otherwise exception handling control flow does not guide you to the next statement behind the call of "new").
2) If you use C++ without exceptions then use "new", too, and check the pointer returned by "new" against 0. To allocate arrays use new[] accordingly. To dynamically resize allocated memory areas use either delete[] and new[] or realloc().
Details: http://www.cplusplus.com/reference/std/ ... tor%20new/
It seems, however, that at least under MSVC++ it is not easy (or even impossible) to have both "throw" and "nothrow" versions available in the same executable.
As to "what the standard says", AFAIK it says that there is a "plain new", a "nothrow new", and a "placement new", just as in the page you linked to. But it does not say, to my knowledge, that all of these are always available under all conditions, and what exactly happens if any of these options is not available.
I did not intend to propose not to use exception handling, just that it obviously has little benefit in chess programs. In my opinion C++ exception handling should be used whenever performance is not an issue. You can concentrate on handling errors in very few places in the program while avoiding to have many functions return an error code which must be checked within huge cascades of "call function1; if (function1 returned an error) ... else ... call function2; if (function2 returned an error) ... else ...". The burden of correctly dealing with allocated memory, or in general of correctly cleaning up resources in case of an error, is almost identical with or without exception handling, but with EH code tends to become somewhat shorter and less error prone (unless you forget to handle exceptions correctly at higher levels). Instead of all these functions returning an error code you can call a couple of "void" functions in a row, and whenever you reach the next call you are sure that the previous call was ok. Also when working with local objects allocated on the stack you have the advantage of automatic destruction on the whole way from throwing up to catching an exception.sje wrote:I agree that exception handling should be not be employed in most user applications. Rather, it should be reserved for real time applications which run with little or no user supervision (e.g., embedded fail-safe boxes for aircraft and spacecraft).
As I said: not really an option for most competitive chess programs since exception handling makes the code slower.
Sven
-
sje
- Posts: 4675
- Joined: Mon Mar 13, 2006 7:43 pm
Re: C++ new()
I fully agree that C++ exception handling should not be used in chess programs. However, my objection is not so much related to performance issues, but rather due to encouraging sloppy coding where a programmer uses exceptions for non-exceptional purposes. I have seen too much code where an exception is just a way to get sneak in a non-local goto and label. Rarely are exceptions used only for truly exceptional cases like processor-on-fire or impending-power-outage.Sven Schüle wrote:As to "what the standard says", AFAIK it says that there is a "plain new", a "nothrow new", and a "placement new", just as in the page you linked to. But it does not say, to my knowledge, that all of these are always available under all conditions, and what exactly happens if any of these options is not available.
I did not intend to propose not to use exception handling, just that it obviously has little benefit in chess programs. In my opinion C++ exception handling should be used whenever performance is not an issue. You can concentrate on handling errors in very few places in the program while avoiding to have many functions return an error code which must be checked within huge cascades of "call function1; if (function1 returned an error) ... else ... call function2; if (function2 returned an error) ... else ...". The burden of correctly dealing with allocated memory, or in general of correctly cleaning up resources in case of an error, is almost identical with or without exception handling, but with EH code tends to become somewhat shorter and less error prone (unless you forget to handle exceptions correctly at higher levels). Instead of all these functions returning an error code you can call a couple of "void" functions in a row, and whenever you reach the next call you are sure that the previous call was ok. Also when working with local objects allocated on the stack you have the advantage of automatic destruction on the whole way from throwing up to catching an exception.
And while it's true as you say that automatic variables will have their destructors called, there's no guarantee that the order of these calls will be exactly what's desired. Further, a pointer on the stack will have its (likely empty) destructor called, what it points to will not and leak memory.
Nearly every single library call return some code indicating success/failure (syshalt breaks this rule on success). These return codes are there for a reason and checking them so that they be locally handled is the way to go.
And this checking code doesn't have to consist of ugly if statements nested twenty deep. I use something like:
Code: Select all
bool isokay = true;
if (isokay)
{
do_stuff_1;
isokay = check_return_code(system_call_that_may_go_sour_1());
};
if (isokay)
{
do_stuff_2;
isokay = check_return_code(system_call_that_may_go_sour_2());
};
if (isokay)
{
do_stuff_3;
isokay = check_return_code(system_call_that_may_go_sour_3());
};
call-destructors-as-needed();
return isokay;
-
lucasart
- Posts: 3243
- Joined: Mon May 31, 2010 1:29 pm
- Full name: lucasart
Re: C++ new()
I would go even further and *dare* say that exceptions are the devil's invention. I started hating C++ and going back to C, when I discovered that exceptions were part of the standard STL in such a way that you just couldn't cleanly get rid of them.sje wrote:I fully agree that C++ exception handling should not be used in chess programs. However, my objection is not so much related to performance issues, but rather due to encouraging sloppy coding where a programmer uses exceptions for non-exceptional purposes. I have seen too much code where an exception is just a way to get sneak in a non-local goto and label. Rarely are exceptions used only for truly exceptional cases like processor-on-fire or impending-power-outage.Sven Schüle wrote:As to "what the standard says", AFAIK it says that there is a "plain new", a "nothrow new", and a "placement new", just as in the page you linked to. But it does not say, to my knowledge, that all of these are always available under all conditions, and what exactly happens if any of these options is not available.
I did not intend to propose not to use exception handling, just that it obviously has little benefit in chess programs. In my opinion C++ exception handling should be used whenever performance is not an issue. You can concentrate on handling errors in very few places in the program while avoiding to have many functions return an error code which must be checked within huge cascades of "call function1; if (function1 returned an error) ... else ... call function2; if (function2 returned an error) ... else ...". The burden of correctly dealing with allocated memory, or in general of correctly cleaning up resources in case of an error, is almost identical with or without exception handling, but with EH code tends to become somewhat shorter and less error prone (unless you forget to handle exceptions correctly at higher levels). Instead of all these functions returning an error code you can call a couple of "void" functions in a row, and whenever you reach the next call you are sure that the previous call was ok. Also when working with local objects allocated on the stack you have the advantage of automatic destruction on the whole way from throwing up to catching an exception.
And while it's true as you say that automatic variables will have their destructors called, there's no guarantee that the order of these calls will be exactly what's desired. Further, a pointer on the stack will have its (likely empty) destructor called, what it points to will not and leak memory.
Nearly every single library call return some code indicating success/failure (syshalt breaks this rule on success). These return codes are there for a reason and checking them so that they be locally handled is the way to go.
And this checking code doesn't have to consist of ugly if statements nested twenty deep. I use something like:No ugly nesting or hard-to-read-code. No goto statements and no exceptions. And an decent optimizer will remove unneeded conditions so that a fault test will immediately branch to silent label at the end of the last conditional.Code: Select all
bool isokay = true; if (isokay) { do_stuff_1; isokay = check_return_code(system_call_that_may_go_sour_1()); }; if (isokay) { do_stuff_2; isokay = check_return_code(system_call_that_may_go_sour_2()); }; if (isokay) { do_stuff_3; isokay = check_return_code(system_call_that_may_go_sour_3()); }; call-destructors-as-needed(); return isokay;
I don't see any good reason to have exceptions anywhere. And I have yet to be proven wrong. For example the Linux Kernel is no more than 13 million of the most sophisticated C code. No exceptions, and no C++. Not a single class or template, even though there are some very complicated object-oriented structures going on there (a good example is the BTRFS file system). If people like Linus Torvaldes think that C++ is the devil's invention, there must be a valid reason!
And yes, goto is taboo. Although there is one case where goto is the right way to proceed: when you have nested loops and need to exit from all the loops at once when something happens. Of course you can always avoid using goto in this case but it makes the code a little more convoluted.
There's nothing worse than C++ written by noobs :p This language is far too complicated to be used by noobs, and it too often is.
-
lucasart
- Posts: 3243
- Joined: Mon May 31, 2010 1:29 pm
- Full name: lucasart
Re: C++ new()
And thinking that years ago, in my (buggy and lame) engine BibiChess 0.5 I threw an exception to brutally stop the recursive search when the time limit was exceeded.lucasart wrote:I would go even further and *dare* say that exceptions are the devil's invention. I started hating C++ and going back to C, when I discovered that exceptions were part of the standard STL in such a way that you just couldn't cleanly get rid of them.sje wrote:I fully agree that C++ exception handling should not be used in chess programs. However, my objection is not so much related to performance issues, but rather due to encouraging sloppy coding where a programmer uses exceptions for non-exceptional purposes. I have seen too much code where an exception is just a way to get sneak in a non-local goto and label. Rarely are exceptions used only for truly exceptional cases like processor-on-fire or impending-power-outage.Sven Schüle wrote:As to "what the standard says", AFAIK it says that there is a "plain new", a "nothrow new", and a "placement new", just as in the page you linked to. But it does not say, to my knowledge, that all of these are always available under all conditions, and what exactly happens if any of these options is not available.
I did not intend to propose not to use exception handling, just that it obviously has little benefit in chess programs. In my opinion C++ exception handling should be used whenever performance is not an issue. You can concentrate on handling errors in very few places in the program while avoiding to have many functions return an error code which must be checked within huge cascades of "call function1; if (function1 returned an error) ... else ... call function2; if (function2 returned an error) ... else ...". The burden of correctly dealing with allocated memory, or in general of correctly cleaning up resources in case of an error, is almost identical with or without exception handling, but with EH code tends to become somewhat shorter and less error prone (unless you forget to handle exceptions correctly at higher levels). Instead of all these functions returning an error code you can call a couple of "void" functions in a row, and whenever you reach the next call you are sure that the previous call was ok. Also when working with local objects allocated on the stack you have the advantage of automatic destruction on the whole way from throwing up to catching an exception.
And while it's true as you say that automatic variables will have their destructors called, there's no guarantee that the order of these calls will be exactly what's desired. Further, a pointer on the stack will have its (likely empty) destructor called, what it points to will not and leak memory.
Nearly every single library call return some code indicating success/failure (syshalt breaks this rule on success). These return codes are there for a reason and checking them so that they be locally handled is the way to go.
And this checking code doesn't have to consist of ugly if statements nested twenty deep. I use something like:No ugly nesting or hard-to-read-code. No goto statements and no exceptions. And an decent optimizer will remove unneeded conditions so that a fault test will immediately branch to silent label at the end of the last conditional.Code: Select all
bool isokay = true; if (isokay) { do_stuff_1; isokay = check_return_code(system_call_that_may_go_sour_1()); }; if (isokay) { do_stuff_2; isokay = check_return_code(system_call_that_may_go_sour_2()); }; if (isokay) { do_stuff_3; isokay = check_return_code(system_call_that_may_go_sour_3()); }; call-destructors-as-needed(); return isokay;
I don't see any good reason to have exceptions anywhere. And I have yet to be proven wrong. For example the Linux Kernel is no more than 13 million of the most sophisticated C code. No exceptions, and no C++. Not a single class or template, even though there are some very complicated object-oriented structures going on there (a good example is the BTRFS file system). If people like Linus Torvaldes think that C++ is the devil's invention, there must be a valid reason!
And yes, goto is taboo. Although there is one case where goto is the right way to proceed: when you have nested loops and need to exit from all the loops at once when something happens. Of course you can always avoid using goto in this case but it makes the code a little more convoluted.
There's nothing worse than C++ written by noobs :p This language is far too complicated to be used by noobs, and it too often is.
I feel ashamed of it now, but at the time I thought that the more C++ stuff I used the better, and that exceptions was the right way to code...
-
Sven
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: C++ new()
Nobody is forced to use all features offered by a language. C++ is definitely an improved C even without classes and objects, exceptions, templates, operator overloading etc. Also there is no need to use STL if you don't like it, you can still use C++ without it.lucasart wrote:I would go even further and *dare* say that exceptions are the devil's invention. I started hating C++ and going back to C, when I discovered that exceptions were part of the standard STL in such a way that you just couldn't cleanly get rid of them.
I don't see any good reason to have exceptions anywhere. And I have yet to be proven wrong. For example the Linux Kernel is no more than 13 million of the most sophisticated C code. No exceptions, and no C++. Not a single class or template, even though there are some very complicated object-oriented structures going on there (a good example is the BTRFS file system). If people like Linus Torvaldes think that C++ is the devil's invention, there must be a valid reason!
Linux was created by Linus Torvalds in 1991. At that time C++ did already exist for few years (first commercial compiler at 1985, I think), albeit not standardized yet. I don't know the exact reasons of Linus to choose C instead of C++ back in 1991 but since the Linux kernel included a lot of assembler code I can imagine that he felt that C were more appropriate for his task. Also it might be possible that the (GNU) C++ compiler technology back then was not mature enough to serve as a good alternative for producing acceptably fast code suitable for the purposes of an operating system. Note, all these are my guesses but I think they are not far-fetched. Linus made public statements about C++ much later, like this one, but I don't know whether these were also his thoughts in 1991, it is also possible that he did not even consider C++ as an option at that time.
A "noob" will not write better programs in C, Java or any other language than in C++. You will never be able to prevent people from using some tool, language, or other thing for which they lack the required qualification. C++ is nothing special here. C is much simpler than C++, agreed, but you still need to be skilled to write good and correct (nontrivial) C software.lucasart wrote:There's nothing worse than C++ written by noobs :p This language is far too complicated to be used by noobs, and it too often is.
I am not here to try converting you back to C++. Everyone has made his own experiences, and everyone works with those languages or tools he prefers most, since that is usually the way to be most efficient and successful. For instance, I like the UNIX text editor "vi" and use it quite extensively. You (or someone else) might argue that "there is a much better editor XY". And that is right for you, but still "vi" is right for me.
More or less the same applies to "C vs. C++". My only concern is, I don't believe it is a good idea to call something "the devil's invention". You, as well as Linus (I only use him as an example since you mentioned him), believe that C is the better choice, and I, as well as others, believe it's C++. But I strongly believe that the success of Linux was not based on using C instead of C++, it was mainly based on Linus Torvalds being a very, very good software developer who also had the right idea at the right time.
So it is as always: there is not the one right answer.
Sven