- question wrt std::result_of - 3 Updates
- A good error case practice - 9 Updates
- A "better" C++ - 6 Updates
- About virtual destructor for polymorhism deletion - 2 Updates
- About virtual destructor for polymorhism deletion - 1 Update
- Deep copying - 2 Updates
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:
Post a Comment