Friday, August 21, 2015

Digest for comp.lang.c++@googlegroups.com - 23 updates in 6 topics

Doug Mika <dougmmika@gmail.com>: Aug 21 12:11PM -0700

Hi, why must I write:
std::result_of<decltype(fn)&(int)>::type b; //what is the & for?
and why can't I write this instead:
std::result_of<fn(int))>::type b; //what is wrong with this?
in my program:
// result_of example
#include <iostream>
#include <type_traits>
 
int fn(int a) {return a;} // function
 
int main() {
int a=3;
//std::result_of<fn(int))>::type b;
std::result_of<decltype(fn)&(int)>::type b;
b=5;
std::cout<<b<<std::endl;
return 0;
}
legalize+jeeves@mail.xmission.com (Richard): Aug 21 08:43PM

[Please do not mail me a copy of your followup]
 
Doug Mika <dougmmika@gmail.com> spake the secret code
> std::result_of<decltype(fn)&(int)>::type b; //what is the & for?
>and why can't I write this instead:
> std::result_of<fn(int))>::type b; //what is wrong with this?
 
fn is not a type, it is an identifier.
 
Use int(int)
 
 
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 22 12:48AM +0200

On 21.08.2015 21:11, Doug Mika wrote:
> std::result_of<decltype(fn)&(int)>::type b; //what is the & for?
> and why can't I write this instead:
> std::result_of<fn(int))>::type b; //what is wrong with this?
 
Well, first off, it's self-inflicted pain to use `result_of` directly
here. Instead write just
 
function<decltype(fn)>::result_type b;
 
where `function` is `std::function`.
 
You need the `decltype` to get the /type/ of the function `fn`.
 
With direct use of `result_of` the type that you supply is a
construction that communicates two things simultaneously to `result_of`:
 
* the full function type, or more generally a /callable/ type, that
you're interested in result type of, call that A, and
 
* the argument types that it should be regarded as called with, call
them B1, B2, ... Bn,
 
Typically you communicate this as A*(B1, B2, ... Bn), which is the type
of a function returning A* and taking arguments B1, B2 ... Bn. In your
code you instead used A&(B1, B2, ... Bn). `result_of` accepts both
variants, but A(B1, B2, ... Bn) can't be used, because functions are not
copyable or movable; you can't have a function returning a function.
 
I don't know why it's done that way for `result_of`. It's inordinately
complicated and just hackish, it doesn't make much sense as client code
interface, and as `std::function` proves it's not necessary. I suspect
that it's due to some internal requirements in early Boost library code.
 
 
> std::cout<<b<<std::endl;
> return 0;
> }
 
Cheers & hth.,
 
- Alf
JiiPee <no@notvalid.com>: Aug 21 06:23PM +0100

If a code is done well, should it have error checking in all places? But
if you do that everywhere the code is filled with try-catch, isnt it?
 
For example if I resize an array should I always there use try-catch to
check an error situation in a professional code? Because its always
possible with new vector allocation that the memory was full.
 
I guess the try-catch block should be put to everywhere where an
exception can be thrown, right?
Paavo Helde <myfirstname@osa.pri.ee>: Aug 21 12:54PM -0500

> possible with new vector allocation that the memory was full.
 
> I guess the try-catch block should be put to everywhere where an
> exception can be thrown, right?
 
Absolutely not! This would defeat the whole purpose of exceptions.
 
You put a try-catch in a place where you know how to handle the error. For
many programs this means a single try-catch in main() where you report the
error and exit the program with an error exit code.
 
hth
Paavo
Victor Bazarov <v.bazarov@comcast.invalid>: Aug 21 01:56PM -0400

On 8/21/2015 1:23 PM, JiiPee wrote:
> possible with new vector allocation that the memory was full.
 
> I guess the try-catch block should be put to everywhere where an
> exception can be thrown, right?
 
No.
 
There should be very few places in your code that are surrounded with
'try' and have a 'catch' supplied, IMHO. The subject of error checking
or how/where/whether to respond to abnormal situations is too vast for
even a newsgroup thread. Have you tried looking for a book? Also, this
is more of a software engineering topic than a language topic. Perhaps
you could ask in 'comp.software-eng'? If they are no longer active, try
looking on the web.
 
V
--
I do not respond to top-posted replies, please don't ask
JiiPee <no@notvalid.com>: Aug 21 07:11PM +0100

On 21/08/2015 18:54, Paavo Helde wrote:
> error and exit the program with an error exit code.
 
> hth
> Paavo
 
You mean that its a pretty good approach (especially with small
programs) just to wrap around the whole code with try-catch. Then if any
part throws this catches all of them? And then one can add try-catch
blocks if there is a special need to somewhere else as well?
"Chris M. Thomasson" <nospam@nospam.nospam>: Aug 21 12:38PM -0700

> "Stefan Ram" wrote in message
> news:exception-20150821201804@ram.dialup.fu-berlin.de...
 
[...]
 
> An important subject that often is missing from text books:
> RAII won't work without a global try-catch!
 
You mean that dtors just might not be called if an exception is thrown
without a
global try-catch?
 
Humm... I did not know that!
 
Yikes!
 
;^o
 
[...]
Paavo Helde <myfirstname@osa.pri.ee>: Aug 21 03:00PM -0500

> programs) just to wrap around the whole code with try-catch. Then if
> any part throws this catches all of them? And then one can add
> try-catch blocks if there is a special need to somewhere else as well?
 
Exactly. Do not catch the exception if you have no idea what to do with
it. For example, putting a try-catch around each vector push_back would
be of no use because you do not know how to handle it, it's too low-level
code. This is the decision of the application, not of the low-level
library code doing push_backs.
 
For example, imagine an image processing program, it can easily run out
of memory deep in some image transformation algorithm which has no idea
from which application it is called from and what would be a sensible
remedy. If it is a non-GUI program then probably the most sensible way is
to have one try-catch in main() and exit the process, if it is a GUI()
program then it might make sense to put try-catch in the main GUI event
loop and notify the user that an action failed and he can try to do
something else. (Though to be honest, memory exhaustion is pretty fatal,
even if your program survives it there is no guarantee that other
programs and the OS will cope with it properly.)
 
Cheers
Paavo
legalize+jeeves@mail.xmission.com (Richard): Aug 21 08:34PM

[Please do not mail me a copy of your followup]
 
no@notvalid.com spake the secret code
 
>If a code is done well, should it have error checking in all places?
 
It should have error *detection* at all the places where errors can be
detected. Usually this is from C style APIs that indicate errors by
return value because C doesn't have exceptions.
 
Let's take a concrete example. In COM programming, methods on COM
interfaces and COM global functions return HRESULT status codes
indicating success or failure. In some cases, an HRESULT may be
tested explicitly because it is "normal" for it to fail -- for
instance opening a file whose name is supplied on the command-line
arguments or through other user input. The user may have simply typed
the filename incorrectly and we want to handle the "can't open file"
error explicitly. In this case, failure is an expected part of normal
interaction.
 
In other cases, the failure is due to a programming error and we
aren't going to build user interface or other specific handling for
this error, but we don't want to ignore it either. In this case,
errors are exceptional and not a part of normal interaction.
 
In my book on Direct3D programming, I showed a technique for mapping
unexpected COM HRESULT failures to C++ exceptions so that your code
has good error detection, the error detection is pushed behind a
simple mechanism that doesn't obscure normal flow, and such errors are
immediately brought to your attention when they occur instead of the
errors accumulating behind the scenes.
 
See section 1.13 Code Techniques on pg. 25 of the PDF:
<http://user.xmission.com/~legalize/book/download/01-Introduction.pdf>
 
>But
>if you do that everywhere the code is filled with try-catch, isnt it?
 
If your code is littered with try-catch blocks, then IMO you haven't
identified your error handling strategy and have approached things in
a haphazard manner.
 
>For example if I resize an array should I always there use try-catch to
>check an error situation in a professional code? Because its always
>possible with new vector allocation that the memory was full.
 
Full or fragmented and the requested size couldn't be obtained as a
single contiguous chunk. The question is: What should I do about
bad_alloc exceptions?
 
For many (most?) applications, the answer is "nothing, really". If
your code was written to be exception safe, then unwinding everything
all the way out to main should gracefully release all resources
acquired so far and then call std::terminate.
<http://en.cppreference.com/w/cpp/error/terminate>
 
There are other applications where a reasonable strategy for handling
std::bad_alloc is to capture it somewhere within an interactive GUI
processing event loop and abort an in-progress operation cleanly,
informing the user that the requested operation could not be completed
because of insufficient memory.
 
>I guess the try-catch block should be put to everywhere where an
>exception can be thrown, right?
 
Again, the question that should be asked here is: what is my error
(exception) handling policy? Where, if anywhere, can or should I
handle unexpected exceptions? Depending on the code you are writing,
the answer can be very different.
 
If I am writing a library and my callers may be from C or some other
language that doesn't support C++ exceptions, then I shouldn't allow
any C++ exceptions to unwind out of any of my external API entry
points. I should catch all exceptions and turn them into some kind of
C style error code that can be inspected by the caller.
 
If I am writing a library intended only to be used from C++, I might
allow exceptions to unwind from my library. However, even here it is
not a rule -- even the standard library has different strategies for
different components. For instance, attempting to extract an int from
an istream that is empty doesn't result in an exception. Even
attempting to open an ifstream on a non-existent file doesn't throw an
exception.
 
The filesystem technical specification generally provides two forms of
operations like "copy_file": one that throws on error and another that
returns an error code on failure. This leaves the choice of the error
handling mechanism up to the caller, but either way the copy_file
operation detects errors.
<http://en.cppreference.com/w/cpp/experimental/fs/copy_file>
 
My general rule of thumbs are:
 
- understand what, if any, error/exception handling strategy your
application should have and then look for the fewest number of places
to apply the error/exception handling. Usually that is just a small
handfull of places. If you're doing a try/catch around every
expression that could potentially throw, you're doing it wrong.
- decide on the error handling policy for all subsystems (should
exceptions throw across the library boundary, for instance?)
- turn all C style error codes into C++ exceptions when the underlying
API call shouldn't fail in the normal course of operation. Let them
break your application.
- most GUI frameworks don't like it when event handlers throw
exceptions up into the GUI framework, so consider "GUI framework
event handlers" to be living at the boundary between systems.
- bad_alloc usually indicates such catastrophic failure that there
usually isn't much you can do about it besides exit which is what will
happen anyway. However, interactive applications may want to
provide the user with one last chance to save unsaved work. This,
in turn, may also fail if it needs to allocate memory in order to
save work.
- avoid C style error status codes for most things and instead prefer
exceptions for unusual/exceptional errors
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Aug 21 08:42PM

[Please do not mail me a copy of your followup]
 
"Chris M. Thomasson" <nospam@nospam.nospam> spake the secret code
 
>You mean that dtors just might not be called if an exception is thrown
>without a global try-catch?
 
The standard says it is implementation defined whether or not the
stack is unwound before calling std::terminate. It doesn't explain
why this is allowed to be defined by the implementation.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
JiiPee <no@notvalid.com>: Aug 21 11:38PM +0100

On 21/08/2015 20:20, Stefan Ram wrote:
> ...So this shows that books and the web are fine, but to really learn
> what matters, one Must Read The Usenet!
 
Thanks, interesting things
Ian Collins <ian-news@hotmail.com>: Aug 21 11:44AM +1200

Alf P. Steinbach wrote:
> name collisions (no compiler firewall here!), but still, since this
> avoids the same header being processed in and every translation unit, it
> reportedly cuts so much off build times that people find it worth doing.
 
It sounds to me like the best way to blow out compile times and system
requirements. It may have been a valid hack a decade or so back, but
with decent tools on multi-core systems it's a really dumb idea.
 
> recovery information, but just gives up on first detected error.
 
> Well, there you have it, decent compilation times also for C++, I believe.
 
> All it requires is ... new compilers. He he. :)
 
:) Or faster computers!
 
--
Ian Collins
David Brown <david.brown@hesbynett.no>: Aug 21 11:40AM +0200

On 21/08/15 01:10, Alf P. Steinbach wrote:
> name collisions (no compiler firewall here!), but still, since this
> avoids the same header being processed in and every translation unit, it
> reportedly cuts so much off build times that people find it worth doing.
 
As Ian says, this will not take much advantage of a multi-core system.
 
One reason I have seen for people joining their C++ files into one is to
get control of the initialisation order of file-scope objects. The
order is determined (by placement in the file) within a compilation
unit, but not across compilation units. It would be nice if there were
a good way to handle this without the mess of initialise-on-first-use.
gcc has attributes to handle this, but they are not perfect - and of
course they are not portable.
 
Another reason is for optimisation - either code space (because older or
more limited compilers can generate duplicate code for templates used in
multiple files), or for speed optimisation (allowing cross-module
optimisations). Link-time optimisation is a better way to handle that
now, at least in many cases.
 
 
> won't be fiddling with per-unit symbols when you specify a bunch of
> files to compile) opting out, perhaps needing to explicitly suppress a
> warning.
 
I think the best way forward here is to make modules part of the C++
language. clang/llvm has a "module" extension - I haven't studied it
much, and don't know whether it is the best solution, but it is the
right sort of idea. Headers and/or source files should be compilable
into a re-usable block that can be accessed from other headers and
source files without re-compiling everything from scratch. This will
place restrictions on what can be in such headers - but that would avoid
the complications that precompiled headers have, such as the influence
the pre-processor can have on the code.
 
scott@slp53.sl.home (Scott Lurndal): Aug 21 01:40PM

>place restrictions on what can be in such headers - but that would avoid
>the complications that precompiled headers have, such as the influence
>the pre-processor can have on the code.
 
You're describing the paradigm we used at Burroughs to build
the operating system (MCP) for a line of mainframes. The language
was called SPRITE (with algol-like and modula-like features) and
the central component was the Module Interface Description (MID)
which included all the types, constants, structure definitions,
global (and module local (i.e. file scope)) variables, module
definitions and function signatures (a la C++ classes).
 
The MID, once compiled, was used by the SPRITE compiler to resolve
all references when a module was subsequently compiled.
 
Centralization in this case had many advantages, and some disadvantages
(serialized access to the MID and full recompiles after MID changes;
and in those days a full build took overnight, even on our fastest
mainframe). This was before modern SCCS tools, so updates to the
MID needed to be carefully coordinated (done via patch decks) which
could be a significant bottleneck during the early development period
when the interfaces between modules were being designed.
 
Given modern memory sizes and the use of available memory as a file
cache by modern operating systems, for any project of size, the majority
of header files included more than once are cached in memory for the
duration of the compile. It takes a very large project (million+ LOC)
to have a substantial compile time on modern multicore desktop CPU's
using a make utility that supports parallelism (e.g. pmake, gmake).
 
With good dependency tools (e.g. makedepend), incremental compiles
are normal and full compiles rare today.
red floyd <no.spam@its.invalid>: Aug 21 10:59AM -0700

On 8/21/2015 6:40 AM, Scott Lurndal wrote:
> definitions and function signatures (a la C++ classes).
 
> The MID, once compiled, was used by the SPRITE compiler to resolve
> all references when a module was subsequently compiled.
 
Back in '84, when I was interviewing (out of college), I interviewed
at Burroughs (in Burbank, CA). They were using SPRITE. By chance,
my portfolio had a fairly large Modula-2 component!
 
Wound up not getting the job (forget why).
scott@slp53.sl.home (Scott Lurndal): Aug 21 07:57PM


>Back in '84, when I was interviewing (out of college), I interviewed
>at Burroughs (in Burbank, CA). They were using SPRITE. By chance,
>my portfolio had a fairly large Modula-2 component!
 
Hm.. I might have actually interviewed you then, depending on
which position you had applied for (I was in the MCP group).
 
We were in Pasadena, however, not Burbank. SPRITE was pretty much
used only in Pasadena (the MCP was written in SPRITE as were the
SPRITE compiler, SPRASM assembler and the LINKER).
 
scott
red floyd <no.spam@its.invalid>: Aug 21 03:35PM -0700

On 8/21/2015 12:57 PM, Scott Lurndal wrote:
 
> We were in Pasadena, however, not Burbank. SPRITE was pretty much
> used only in Pasadena (the MCP was written in SPRITE as were the
> SPRITE compiler, SPRASM assembler and the LINKER).
 
May have been Pasadena, was a hell of a long time ago. I was
interviewing with the compiler group.
Udo Steinbach <trashcan@udoline.de>: Aug 21 02:56PM +0200

> Now you will have to somehow find out which exact class you have, maybe by
> repeated dynamic_casts, and huge if-else blocks for executing the correct
> delete.
 
or carry an extra pointer, http://www.thradams.com/codeblog/type_ptr3.htm
--
Fahrradverkehr in Deutschland: http://radwege.udoline.de/
GPG: A245 F153 0636 6E34 E2F3 E1EB 817A B14D 3E7E 482E
ram@zedat.fu-berlin.de (Stefan Ram): Aug 21 07:20PM

>If a code is done well, should it have error checking in all places? But
>if you do that everywhere the code is filled with try-catch, isnt it?
 
Your code should be »exception safe« under many circumstances.
 
>For example if I resize an array should I always there use try-catch to
>check an error situation in a professional code? Because its always
>possible with new vector allocation that the memory was full.
 
This depends on the software requirements specification
and the implementation design. If there would be a general
rule, it would have been hardcoded into the language.
Instead it is the duty of the programmer to decide what
to do under which cirumstances.
 
If you have a short program for a statistical evaluation,
that should take some seconds of run-time and does not
change data on disk, it can be ok for the program just to
abort with a message. But if the program is a text processor
and has unsaved typed-in data in its buffers, we must take
care that we never lose (discard) any unsaved buffers of the
user!
 
An important subject that often is missing from text books:
RAII won't work without a global try-catch! I learned it from
the Usenet, where I was told:
 
»It's unspecified whether stack unwinding happens when
there is no handler for an exception.«
 
So this shows that books and the web are fine, but to really
learn what matters, one Must Read The Usenet!
Paavo Helde <myfirstname@osa.pri.ee>: Aug 21 12:50PM -0500

Udo Steinbach <trashcan@udoline.de> wrote in
>> executing the correct delete.
 
> or carry an extra pointer,
> http://www.thradams.com/codeblog/type_ptr3.htm
 
Looked at this page. Looks to me mostly like Boost.Any except for the
select<> template which performs all these repeated if checks and type
comparisons under the carpet, to figure out the actual type. But yes, in
overall it seems like a nifty way to add polymorphism to types which don't
have any.
 
And yes, this solution indeed contains an example of appropriate usage of:
 
delete (T*) p;
 
(a better style would be of course to use static_cast<T*>(p)).
 
Cheers
Paavo
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 21 02:47PM +0200

On 19.08.2015 09:34, Paul wrote:
 
> I realise that this was not intended as a c++ question, but I can't
> see a way to do this in c++ because of the huge generality of the
> question, even though I have a basic understanding of deep copying.
 
 
template< class Type >
auto deepCopy( Type&& o ) -> std::remove_ref<Type> { return o; }
 
 
(Not sure of the remove_ref, look it up, but thereabouts)
 
This gives you a logical deep copy, which is all you need. E.g. with g++
old COW strings it will defer the actual copying and just increment a
ref count. Physical deep copying is, as you note, generally impossible
in a type-independent way.
 
 
Cheers & hth.,
 
- Alf
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Aug 21 03:28PM +0100

On 21/08/2015 13:47, Alf P. Steinbach wrote:
>> question, even though I have a basic understanding of deep copying.
 
> template< class Type >
> auto deepCopy( Type&& o ) -> std::remove_ref<Type> { return o; }
 
No need to use 'auto' here unless you are an autsy like Alf.
 
/Flibble
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: