Thursday, January 7, 2021

Digest for comp.lang.c++@googlegroups.com - 25 updates in 4 topics

Lynn McGuire <lynnmcguire5@gmail.com>: Jan 06 05:26PM -0600

On 1/5/2021 3:14 AM, Paavo Helde wrote:
 
>> Wow, we do not have any asserts in our 450,000 lines of C++ code.
 
> For comparison, we have 7708 asserts in 600,000 lines of C++ code. I
> guess this depends on the project type very much.
 
We put in extensive tests that run both in debug and release modes.
 
BTW, my software also has 850,000 lines of Fortran code also for a total
of 1.3 million lines of F77 and C++.
 
Lynn
David Brown <david.brown@hesbynett.no>: Jan 07 09:42AM +0100

On 06/01/2021 22:35, Scott Lurndal wrote:
 
 
> static_assert is quite useful, however, in C++ code.
 
I'd go further and say static assertions are extremely useful in C and
C++ code, and have been so from long before they were added to the
languages. (Prior to C11/C++11 they could be done with some ugly macros.)
 
They have no costs at run-time, serve to document assumptions or
requirements, and make code more robust. As has been noted in this
thread, run-time assertions have run-time costs and open questions such
as what to do when the assertion fails, and how you test the assertion
(untested error handling code is not a good idea) - static assertions
have no such complications.
Ian Collins <ian-news@hotmail.com>: Jan 07 10:21PM +1300

On 07/01/2021 21:42, David Brown wrote:
> as what to do when the assertion fails, and how you test the assertion
> (untested error handling code is not a good idea) - static assertions
> have no such complications.
 
An effective way to test assertion failures is to have them throw an
exception when running unit tests.
 
--
Ian.
David Brown <david.brown@hesbynett.no>: Jan 07 10:37AM +0100

On 07/01/2021 10:21, Ian Collins wrote:
>> have no such complications.
 
> An effective way to test assertion failures is to have them throw an
> exception when running unit tests.
 
But if those assertions are still in the final code, configured to do
something else (log an error, restart the system, or whatever), then you
are not testing the actual code.
 
Many failures in real systems have been caused by people putting in
extra checks "just to be sure" without proper verification of how those
checks work and what happens if they trigger.
Paavo Helde <myfirstname@osa.pri.ee>: Jan 07 02:35PM +0200

07.01.2021 11:37 David Brown kirjutas:
 
> But if those assertions are still in the final code, configured to do
> something else (log an error, restart the system, or whatever), then you
> are not testing the actual code.
 
Over the years I have made up my mind about assertions: these are just
development and debugging aids and should not be present in released code.
 
The same holds for other assert-like features like MSVC checked
iterators. Even MS have figured it out by now, see
"https://docs.microsoft.com/en-us/cpp/standard-library/checked-iterators?view=msvc-160"
:
 
"By default, the value for _ITERATOR_DEBUG_LEVEL is 0 for release builds
and 2 for debug builds."
 
YMMV, of course.
 
 
> Many failures in real systems have been caused by people putting in
> extra checks "just to be sure" without proper verification of how those
> checks work and what happens if they trigger.
 
Agreed.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jan 07 09:23AM -0500

On 1/7/21 7:35 AM, Paavo Helde wrote:
...
> Over the years I have made up my mind about assertions: these are just
> development and debugging aids and should not be present in released code.
 
If you have such aids disabled in the released code, the code should be
thoroughly tested with those aids disabled, before being released.
Paavo Helde <myfirstname@osa.pri.ee>: Jan 07 05:37PM +0200

07.01.2021 16:23 James Kuyper kirjutas:
>> development and debugging aids and should not be present in released code.
 
> If you have such aids disabled in the released code, the code should be
> thoroughly tested with those aids disabled, before being released.
 
Not sure if you meant s/disabled/enabled/ in the last line. With
"enabled" I agree of course, with "disabled" not.
 
A non-op is a non-op, and all such aids must be non-ops if not triggered
(and fixed ASAP when triggered). If some developer writes non-op asserts
then it's a disciplinary problem, not a technical one.
Paavo Helde <myfirstname@osa.pri.ee>: Jan 07 05:39PM +0200

07.01.2021 17:37 Paavo Helde kirjutas:
> If some developer writes non-op asserts
> then it's a disciplinary problem, not a technical one.
 
Heh, wrote the opposite myself here, please s/non-op/non-non-op/ ;-)
James Kuyper <jameskuyper@alumni.caltech.edu>: Jan 07 10:53AM -0500

On 1/7/21 10:37 AM, Paavo Helde wrote:
>> thoroughly tested with those aids disabled, before being released.
 
> Not sure if you meant s/disabled/enabled/ in the last line. With
> "enabled" I agree of course, with "disabled" not.
 
No, I meant disabled. You need to test the code as delivered, it may
malfunction in ways that are different from the way it functions when
those aids are enabled.
 
> A non-op is a non-op, and all such aids must be non-ops if not triggered
> (and fixed ASAP when triggered).
 
Those aids should be no-ops when disabled - but assuming that they
actually are no-ops is a bad idea. Among other things, their absence may
affect the way that other code is optimized.
Richard Damon <Richard@Damon-Family.org>: Jan 07 10:56AM -0500

On 1/7/21 10:37 AM, Paavo Helde wrote:
 
> A non-op is a non-op, and all such aids must be non-ops if not triggered
> (and fixed ASAP when triggered). If some developer writes non-op asserts
> then it's a disciplinary problem, not a technical one.
 
The key is that if you had the tests in place for development, you may
run into an issue that removing the tests break the code. This can
happen if the test have some unnoticed side effect, that omitting
creates a problem.
wij <wyniijj@gmail.com>: Jan 07 08:02AM -0800

On Wednesday, 6 January 2021 at 16:19:41 UTC+8, Paavo Helde wrote:
 
> This probably also depends on the project type. Imagine implementing
> something like JPEG compression algorithm, what are the chances a human
> reviewer would notice an one-off mistake somewhere deep in the algorithm?
 
If broken down:
 
#define ASSERT(expr) \ // 1.executable comment (run-time check)
if(!expr) { \ //
cerr << #expr; \ // 2.print expr
abort(); \ // 3.abort
}
 
I rarely use assert because of (2) and (3).
If I am to implement a complex algorithm like JPEG compression, I would
write something like:
if(cond==false) {
THROW(-1) // register __FILE__, __LINE__ and throw a general error
}
But, in general, such codes are not common ( implement complex algorithm is
not a common task)
Paavo Helde <myfirstname@osa.pri.ee>: Jan 07 08:37PM +0200

07.01.2021 17:53 James Kuyper kirjutas:
 
> Those aids should be no-ops when disabled - but assuming that they
> actually are no-ops is a bad idea. Among other things, their absence may
> affect the way that other code is optimized.
 
Just compiling in release mode will affect how the code is optimized, no
need to bring debug asserts into play.
 
And of course the final code needs to be tested (and even more than
debug builds), it's just that removal of asserts is not a major or even
a minor reason for that.
 
Of course, disabling an assert may hide or obfuscate an existing bug,
but I have never seen a bug *created* by disabling an assert. On the
other hand I have seen multiple problems caused by over-eager asserts
left in the code. I believe my rants about MSVC checked iterators can
still be found in ancient c.l.c++.m archives.
Paavo Helde <myfirstname@osa.pri.ee>: Jan 07 09:00PM +0200

07.01.2021 18:02 wij kirjutas:
> }
> But, in general, such codes are not common ( implement complex algorithm is
> not a common task)
 
The exact definition of the assert macro is not so important because one
can always run the code in the debugger and put a breakpoint in the
failure branch. But yes, our asserts throw exceptions instead of abort()
as these are easier to manage.
 
If asserts are disabled in release, then they have zero cost and one can
freely use them also in non-complex code, to protect against typos,
copy-paste errors, etc. For example, just today I wrote:
 
std::string src = /*...*/;
// add zero padding; leave room for 16-byte MD5 hash.
unsigned int k = (src.length()+16) % enc.MandatoryBlockSize();
if (k!=0) {
k = enc.MandatoryBlockSize() - k;
}
src.resize(src.length()+16+k);
DEBUG_ASSERT(src.length() >= 16);
DEBUG_ASSERT(src.length() % enc.MandatoryBlockSize() == 0);
 
Silly asserts (esp the 1st), but I feel more confident I have not
mistyped anything, and that if I change something in the future there
are less chances I screw it up. The asserts also document the needed
preconditions for next lines.
Bonita Montero <Bonita.Montero@gmail.com>: Jan 07 08:17AM +0100

> One other nitpick... Make sure that your:
> atomic<uint64_t>   atomicValue;
> Is isolated: Aligned and padded on a cache line boundary.
 
That's automatically done through the /-8-alignment of the
compiler.
Bonita Montero <Bonita.Montero@gmail.com>: Jan 07 09:04AM +0100

The XCHG-loop was incorrect:
 
#if defined(_MSC_VER)
#include <Windows.h>

No comments: