- Some C++14 code - 10 Updates
- C++ problem - 1 Update
- garbage collection - 4 Updates
- ITipInvocation.Toggle() fails BIG TIME if it's called more than once a second. - 2 Updates
- auto return type - 1 Update
- "Jonathan Blow: "C++ is a weird mess"" - 3 Updates
- Namespace indentation - 3 Updates
- Concept for location - 1 Update
Tim Rentsch <txr@alumni.caltech.edu>: Jul 18 11:49AM -0700 >> practice arrays/vectors nearly always do better. > That's completely true, but in this case it may be a micro-optimization, > even premature optimization, with little to no benefit. The (snipped) suggestion is to consider, and possibly investigate, an alternate approach. Considering and possibly investigating is not optimization, either micro-, premature, or otherwise. > The advantage of using std::list is that the code becomes simpler, > and thus the likelihood of bugs is smaller. > Know your tools, and use them efficiently. I don't want to be rude, but you are taking a lecturing tone with people whose understandings are deeper than your own. |
Paavo Helde <myfirstname@osa.pri.ee>: Jul 16 03:45PM +0300 On 16.07.2018 13:20, Bart wrote: >> using cppx::Range_; >> const auto identstarter = Set_<char>{} >> + Range_{ 'A', 'Z' } + Range_{ 'a', 'z' } + '_' + '$'; [...] > But what is the underlying data-structure? Pascal-like sets might use a > bitmap so the test for 'in' is a simple bit-test (after checking for > range and locating the byte where the bit will be). Alf's Set_ is a template probably taking any type which has a comparison operator defined. C++ has std::bitset which could be used automatically for a limited range datatype like char. Not sure if this actually a case or if it would be a good idea at all, too much automatism is not always good either. Maybe define another class like LimitedRangeSet or something. For comparison, here is a solution using only C++ standard classes. It requires some helper functions to simplify the usage. As Alf said, C++ tends to give you the building blocks, not the ready-made solution. In a proper C++ solution these functions should probably go into a custom class for more encapsulation, this is just a minimal example. #include <iostream> #include <bitset> #include <limits> constexpr char kMin = std::numeric_limits<char>::min(); constexpr char kMax = std::numeric_limits<char>::max(); using set = std::bitset<kMax-kMin+1>; set Range(char a, char b) { set x; while (a<=b) { x.set(a++ - kMin); } return x; } set Elem(char a) { return Range(a, a); } bool In(char c, const set& x) { return x[c-kMin]; } int main() { set identstarter = Range('A', 'Z') | Range('a', 'z') | Elem('_') | Elem('$'); set identbody = (identstarter | Range('0', '9')) & ~Elem('Z'); // exclude Z char c = 'Z'; if (In(c, identstarter)) { std::cout << c << " is in identstarter\n"; } if (In(c, identbody)) { std::cout << c << " is in identbody\n"; } } |
bitrex <user@example.net>: Jul 19 01:32PM -0400 > bothered about calling free then just use alloca() and allocate on the stack. > No free() required though there may be limits on how much memory the OS or > CPU will allow. alloca() is non-portable, and some implementations are bugged. "May be limited" in practice means "Always by default very limited on all modern PC architectures and OSes." |
Bo Persson <bop@gmb.dk>: Jul 18 12:14PM +0200 On 2018-07-18 09:50, Tim Rentsch wrote: > I wasn't offering any opinion about how much C++ is to write home > about. My comment is only about the laughable proposition that > C++-minus-templates is only mildly larger than C. Yeah! One data point: K&R "The C Programming Language" - 200 pages Stroustrup "The C++ Programming Language" - 1300 pages Bo Persson |
Tim Rentsch <txr@alumni.caltech.edu>: Jul 18 12:48AM -0700 >> "a mild superset". That's a good one. :) > It is better to say that C++ has compatibility with C, then speaking in > terms of superset. My comment was not about the superset part, only about the mild part. |
Tim Rentsch <txr@alumni.caltech.edu>: Jul 18 12:50AM -0700 > Without metaprogramming (and all the stuff that utilizes template > metaprogramming like the STL) C++ really isn't much to write home > about in the year of our Lord 2018. I wasn't offering any opinion about how much C++ is to write home about. My comment is only about the laughable proposition that C++-minus-templates is only mildly larger than C. |
Bart <bc@freeuk.com>: Jul 16 05:33PM +0100 On 16/07/2018 15:59, Paavo Helde wrote: >> subelem(identbody,'Z'); > I notice this is 10 lines/statements of *usage* in C as compared to the > 2 lines in C++, Unless it's ultra-simple like the script version, multiple simple lines can be better than cramming more stuff on one line. But if the line count matters, then the C can be tweaked so that addrange() etc return their set parameter. Then it's three lines (plus declarations): addelem(addelem(addrange(addrange(identstarter,'A','Z'), 'a','z'),'_'),'$'); memcpy(identbody,identstarter,sizeof(Set)); subelem(addrange(identbody,'0','9'),'Z'); Or two lines if changed to pass and return sets by value. But to go back to an earlier point, this sort of stuff really belongs in a higher level language (higher level than C++), otherwise the use of it seems laboured. And the implementation of it (I've glanced at Alf's headers) has to be reprocessed on each build too. For example, you wouldn't write this even in C++: if (!In(c, Elem(cr) | Elem(lf) | Elem(tab) | Elem(space)) ... like my other script example, because it would be over the top. (And you can sense the amount of machinery required to make it work, even if it can eventually be optimised down to little). You would write this: if (!(c == cr || c == lf || c == tab || c == space)) ... which also has short-circuit evaluation as well as being less likely to have people scratching their heads. (FWIW I don't try to emulate such sets when writing at the level of C. I use character maps (char[256]) directly without pretending they are sets. They are initialised via a loop over 0 to 255 so the issue of a set constructor doesn't arise. As I also said elsewhere you adapt to the language. Having said that, fixed-size sets using bitmaps (and Ranges as a separate type) /could/ be built-in to a C-type language, and the handling of them can be made lightweight enough that they could be used with spontaneity and with little overhead, especially when the set fits into a machine word. But I haven't done that myself because I don't write enough code in such a language; I would use the next one up!) -- bart |
Juha Nieminen <nospam@thanks.invalid>: Jul 18 07:53AM > A good suggestion IMO. A problem with lists (as I think Bjarne has > pointed out) is they suffer from lack of cache locality, so in > practice arrays/vectors nearly always do better. That's completely true, but in this case it may be a micro-optimization, even premature optimization, with little to no benefit. I this were a number-crunching example, where the list of elements is being traversed and modified millions of times per second, as fast as the computer can possibly do it, I would never use a linked list (unless it's absolutely necessary, which is the case with a few algorithms; rarely, but they exist). However, this example is a list of a couple dozen elements, give or take, which is traversed and modified once per frame (ie. typically 60 times per second). It's hardly a bottleneck. Moreover, depending on the particular implementation, the projectiles themselves may be dynamically allocated objects (which is very common with many game engines, where sprites are typically dynamically allocated), so you are not really saving a lot of dynamic allocations by not using a linked list. The advantage of using std::list is that the code becomes simpler, and thus the likelihood of bugs is smaller. Know your tools, and use them efficiently. |
Bart <bc@freeuk.com>: Jul 16 03:27PM +0100 On 16/07/2018 13:45, Paavo Helde wrote: > } > bool In(char c, const set& x) { > return x[c-kMin]; In general this needs a range check, as you want indices outside the span of the set to return 0. Here you've arranged the index to be an char type with the same limits as the set. The problem is that someone might pass 1000000, which is silently narrowed to char (is it, in C++?), so then it becomes 64. Which is not in the set. But 1000001 (65) apparently will be. This is part of a more general problem, but using narrow function parameters, it's just more likely to go wrong. > std::cout << c << " is in identbody\n"; > } > } You can simplify it further. Below is a version in C that uses byte-maps rather than bit-maps, which is OK for small sets. Apart from the function syntax, it's not so objectionable. However this was simple because I've used a fixed Set type (and assumed that 'char' is unsigned and that character codes are ASCII). Below the C code, is reminder of the script version. There, the feature is often used trivially just to do a multiple compare: while ch not in [cr, lf, space, tab] do ... (With byte-code, this can be faster than doing up to four lots of compares.) Expressivity at work... ---------------------------------- // C code #include <stdio.h> #include <string.h> typedef char Set[256]; Set identstarter; Set identbody; void clearset(Set e){ memset(e,0,sizeof(Set)); } void addrange(Set e,int a,int b){ while (a<=b) e[a++]=1; } void addelem(Set e,int a){ // these should be range-checked, but a bad e[a]=1; // value is a coding error; passing out- // out-of-range index to in() is OK } void subelem(Set e,int a){ e[a]=0; } int in(int a, Set e){ if (a<0 || a>=256) return 0; return e[a]; } void printset(char* caption,Set e){ int i; printf("%s = [",caption); for (i=0; i<256; ++i) if (e[i]) if (i>32 && i<127) printf("%c ",i); else printf("0x%02X ",i); puts("]"); } int main(void) { int c; clearset(identstarter); addrange(identstarter,'A','Z'); addrange(identstarter,'a','z'); addelem(identstarter,'_'); addelem(identstarter,'$'); memcpy(identbody,identstarter,sizeof(Set)); addrange(identbody,'0','9'); subelem(identbody,'Z'); printset("Identstarter",identstarter); printset("Identbody",identbody); c='Z'; printf("%d\n", in(c, identstarter)); printf("%d\n", in(c, identbody)); } --------------------------------- proc start= identstarter := ['A'..'Z', 'a'..'z', '_', '$'] identbody := identstarter + ['0'..'9'] - ['Z'] c:='Z' println c in identstarter println c in identbody end -- bart |
Manfred <noname@add.invalid>: Jul 16 03:12PM +0200 On 7/16/2018 2:51 PM, Scott Lurndal wrote: > and understanding the difference between production code and whatever > a debug build might be (none of us program on windows systems or use > VS - for us, a debug build omits -O3). Still one question remains: was it unique_ptr or shared_ptr's that you removed (or both)? The difference is relevant. That said, blindly replacing all raw pointers with smart pointers is a misuse, I agree with you need to know what you are doing and choose appropriately. (by the way, you know that with gcc omitting -O3 is equivalent to -O0) |
jacobnavia <jacob@jacob.remcomp.fr>: Jul 18 09:54PM +0200 Le 18/07/2018 à 11:16, Ian Collins a écrit : > Old clang? Exactly. That was the problem. Thanks Ian. jacob |
Soviet_Mario <SovietMario@CCCP.MIR>: Jul 17 03:38AM +0200 Il 15/07/2018 18:34, Paavo Helde ha scritto: > In C++ the only sensible way to have GC is to logically > think that all allocated objects are leaked, but that's ok > as you have got infinite memory. Uh ... what do you actually mean with this "you have infinite memory" ? To use it up freely, never caring, and to simply rely on try/catch/finally in case some error occurs ? > Behind the scenes the > memory gets reused of course, again I can't understand. Do you mean at the OS' memory management level ? Or by some "hidden" code generated by modern compilers ? Or even sth else ... > released properly and are not left to GC which will run in > unpredictable times in a random thread. > I believe the current consensus is that with RAII one can at the very outdated time I firstly read of RAII, memory allocation was one of such resources. Why this distinction now ? > control both memory and non-memory resources in the same way > and with less hassle, so RAII all the way down it is. Thus > GC is effectively not needed in C++. SNIP ah, another question ... when you speak of POOLS, you mean allocating on the heap (or even statically) a big contiguous chunk and then overload new/delete into more specialized (and faster) forms which pick up some space within that chunk ? Ciao -- 1) Resistere, resistere, resistere. 2) Se tutti pagano le tasse, le tasse le pagano tutti Soviet_Mario - (aka Gatto_Vizzato) |
Vir Campestris <vir.campestris@invalid.invalid>: Jul 16 09:20PM +0100 On 16/07/2018 13:52, Andrew Goh wrote: > thanks for all the responses, actually coming from the java world c++ is quite as 'native' to me, i'd guess most 'java programmers' (and so do other similar managed languages) are somewhat spoilt by garbage collection. I have a satnav that runs Android, so the app will be Java. Every few weeks I have to reboot it. It usually goes deaf (ignores voice control); sometimes it doesn't switch between day and night correctly; and every so often it plain crashes and burns. To me it's obviously got some kind of resource leak. Andy |
Rosario19 <Ros@invalid.invalid>: Jul 17 11:09AM +0200 On Mon, 16 Jul 2018 21:20:24 +0100, Vir Campestris wrote: >and every so often it plain crashes and burns. To me it's obviously got >some kind of resource leak. >Andy the leak can be in C++ even if there are no leak, if the allocator (malloc()/free() or new()/delete()) not has one algo for return to OS the memory (zeroed first) that can |
Rosario19 <Ros@invalid.invalid>: Jul 17 11:10AM +0200 On Tue, 17 Jul 2018 11:09:21 +0200, Rosario19 wrote: >the leak can be in C++ even if there are no leak, >if the allocator (malloc()/free() or new()/delete()) not has one algo >for return to OS the memory (zeroed first) that can the leak can be in C++ even if there are no leak, if the allocator (malloc()/free() or new()/delete()) not has one algo for free to OS the memory (zeroed first) that can |
Jeff-Relf.Me @.: Jul 23 03:12AM -0700 |
boltar@cylonHQ.com: Jul 17 09:03AM On Mon, 16 Jul 2018 19:31:37 +0300 >> and Windows 10 is no different. >There are lots of computers where there is no C:\Program Files, but for >example C:\Programme or C:\Archivos de programa. Thats just fuckwittery on the part of Microsoft. You wouldn't go into a unix install in france or spain and expect to see /maison or /casa instead of /home. Major OS paths should be standardised no matter what the locale. |
Tim Rentsch <txr@alumni.caltech.edu>: Jul 18 12:47AM -0700 > I guess the case of having side effects qualifies as not a "core > constant expression" which in n4659 10.1.5 p5 results in an ill-formed > program, without warning (I hate those) My reading of this passage is that the program is ill-formed only if the function cannot possibly be called to deliver a constexpr result. As long as there is some way of calling it to deliver a constexpr result, it's okay to call it other ways that result in runtime evaluation. Yes? |
scott@slp53.sl.home (Scott Lurndal): Jul 20 01:10PM >>> essentially the same environment I had in 1988. >> If it works for them, why should they change? >30 years ago I was writing C. C worked for me, why should I change? False analogy. In any case, there is quite a bit of C code still being developed and maintained. |
legalize+jeeves@mail.xmission.com (Richard): Jul 20 08:51PM [Please do not mail me a copy of your followup] Vir Campestris <vir.campestris@invalid.invalid> spake the secret code >30 years ago I was writing C. C worked for me, why should I change? If your needs haven't progressed beyond what you were writing 30 years ago, then no need to change. A current example of where that might be the case is coding for small embedded processors. There is limited memory and ROM storage space, so the kinds of situations where large scale problems appear just don't occur. However, I find myself working in larger problem spaces now and C doesn't scale well to larger code bases because of its limited ability to express abstractions directly in code. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Terminals Wiki <http://terminals-wiki.org> The Computer Graphics Museum <http://computergraphicsmuseum.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
boltar@cylonHQ.com: Jul 19 03:08PM On Thu, 19 Jul 2018 14:29:52 GMT > public c_rx_src_interface, > public c_memory_accessors >class c_zyx: public c_device, I hope your real class names are better than c_xyz and c_zyx! >to that - it automatically creates a thread and invokes the >derived class 'run' function from that thread after the >derived class constructor completes). And if the derived class constructor doesn't complete but throws an exception? Presumably you have to tell the thread not to bother in the exception handler. That seems a rather obtuse and error prone way to obtain a new thread. |
Tim Rentsch <txr@alumni.caltech.edu>: Jul 18 11:16AM -0700 > easily becomes a mess... > I know it's a matter of personal preference (or rules agreed by the team), > but I'm curious what your preference is, and why. I don't have any hard-and-fast rule. Generally, though, I find that indenting nested constructs becomes counterproductive when what is being nested exceeds some length. I don't know what that length is exactly but for concreteness let me call it 100 lines. Below threshold, especially when what is being nested fits on a single 50- or 60- line page, indenting is okay. Above threshold, indenting hurts more than it helps, and it's better just not to indent at all. Related comment: any nesting construction where what is being nested exceeds some relatively small amount (50 lines, say) deserves a comment on its end marker indicating what is being closed. I recommend this practice whether or not the nested portion is indented. |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jul 17 10:06PM -0700 On 7/17/2018 3:19 PM, Vir Campestris wrote: > } > } > I seem to be in a minority. I have indented them all before. It does seem to have potential scaling issues wrt deeply nested namespaces. |
Ian Collins <ian-news@hotmail.com>: Jul 18 06:34PM +1200 On 18/07/18 17:06, Chris M. Thomasson wrote: >> I seem to be in a minority. > I have indented them all before. It does seem to have potential scaling > issues wrt deeply nested namespaces. Mitigate by sticking to two space indentation, or use nested namespace as Flibble showed. -- Ian |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 20 05:06AM +0200 > I have two scenarios: > - Enforce at compile time that an object can only be instanciate on > the stack. This is to implement a "safe" dynarray type like object. Since you mention elsewhere that the /purpose/ is to use stack allocation like a VLA or alloca, there is as far as I know no portable way to differentiate whether an object is allocated in automatic memory, as a static variable, or as part of an array or class type object that in turn can be allocated anywhere. Semi-portably you might compare the object's address to an address obtained in `main`, assuming that the stack has some maximum size (that you might infer from a preprocessor symbol) and that it grows down in memory (again probably best to let the build commands specify). That approach gives you runtime checking. As a convenience measure, getting some ungood usage errors up front at compile time, I would then "= delete" the class' allocation functions, `operator new` and `operator new[]`. > - Enforce at compile tiem that an object can only be instanciate on > the heap. This is to ensure That no "Big" object are instanciated > on the stack. I would make the destructor non-public, i.e. implement the restriction with one or two lines: protected: virtual ~Dynamic_only() {} That works nicely with e.g. `std::make_shared`, at the cost of having to use a simple wrapper function. It doesn't work quite so nicely with `std::make_unique`, requiring per-class boilerplate code. But doable, as exemplified below. The `std::make_shared` support below, the `std::make_shared` wrapper, can easily be moved to a reusable mix-in class, I think. Note: the FAQ instead recommends making the constructors non-public and defining factory functions. In C++03 that wasn't so practical, requiring one factory function per constructor. And so I argued a bit with Marshall Cline (the FAQ maintainer at the time), to change the FAQ to recommend the non-public destructor approach, but to no avail. However, with C++11 we now have ~perfect argument forwarding, so that the umpteen factory functions of C++03 can be rolled into one per class, so that the FAQ's advice isn't so impractical anymore. :) So that's an alternative. However I like being able to use the usual instantiation code instead of calling factory functions. ---------------------------------------------------------------------- #include <memory> // std::make_shared #include <type_traits> // std::is_base_ #include <utility> // std::(enable_if_t, forward) using namespace std; template< class T > using ptr_ = T*; template< class T > using ref_ = T&; class Dynamic_only { protected: virtual ~Dynamic_only() {} public: Dynamic_only() {} Dynamic_only( const int, const int, const int ) {} // A default unique_ptr doesn't store a unique deleter, so one must // use indirection via a specialization of std::default_delete. This // works for direct use of this class, but a derived class needs to // duplicate the effort. std::unique_ptr is just deleter-challenged, // which is a cost of zero overhead for the default instantiation. static void destroy( ptr_<Dynamic_only> p ) { delete p; } // A default shared_ptr stores a unique deleter obtained at the point // where the shared_ptr is constructed, e.g. in the return stm below: template< class... Args > static auto make_shared( Args&&... args ) -> shared_ptr<Dynamic_only> { struct Accessible: Dynamic_only { using Dynamic_only::Dynamic_only; // Constructors. ~Accessible() override {}; // Just to be explicit. }; return std::make_shared<Accessible>( forward<Args>( args )... ); } }; #ifndef TEST_UNSUPPORTED_MAKE_UNIQUE // Annoyingly verbose support for std::unique_ptr: namespace std { template<> struct default_delete<Dynamic_only> { constexpr default_delete() noexcept {} template< class U , class = enable_if_t< is_convertible_v< ptr_< U >, ptr_< Dynamic_only > > > default_delete( ref_<const default_delete<U>> ) noexcept {} void operator()( const ptr_<Dynamic_only> p ) const { Dynamic_only::destroy( p ); } }; } // namespace std
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment