- constexpr function parameter and static_assert - 3 Updates
- "Why < cstlib > is more complicated than you might think" - 12 Updates
- About deleting extra memory from std::vector - 1 Update
Ian Collins <ian-news@hotmail.com>: Mar 05 10:09AM +1300 On 03/05/16 03:02, Öö Tiib wrote: > // ... do what you need > return 0; > } That is basically the fiddle I came up with. The compiler errors are a little obscure, but a comment fixes that. I added This: constexpr int checkRange( int n ) { (n < 1000) ? true : throw 0; return n; } constexpr int f( int n ) { checkRange( n ); return n; } It looks like the latest g++ has trouble spotting this in some conditions, for example given these two lines: constexpr int x {f(1000)}; char buf[f(8000)]; g++ >=5 spots the first as an error, but not the second. g++ 4.9 just spits the dummy and runs. Oracle CC spots them both: Error: Initializer for constexpr variable x must be a constant expression. Error: An integer constant expression is required within the array subscript operator. -- Ian Collins |
"Öö Tiib" <ootiib@hot.ee>: Mar 04 02:39PM -0800 On Friday, 4 March 2016 23:09:40 UTC+2, Ian Collins wrote: > little obscure, but a comment fixes that. I added This: > constexpr int checkRange( int n ) { > (n < 1000) ? true : throw 0; return n; } More often people merge there like: constexpr int checkRange( int n ) {return (n < 1000) ? n : throw 0;} > char buf[f(8000)]; > g++ >=5 spots the first as an error, but not the second. g++ 4.9 just > spits the dummy and runs. The g++ has some sort of variable-length automatic arrays extension so it somehow weasels out using that on second case I suspect. > Error: Initializer for constexpr variable x must be a constant expression. > Error: An integer constant expression is required within the array > subscript operator. Yes, compiler makers are humans too and sometimes mix up when it is "ill-formed" so they have to diagnose and when it is "undefined behavior" so they may screw us. The constexpr is relatively new so we have to calmly fire the bugs for some years. |
Ian Collins <ian-news@hotmail.com>: Mar 05 11:55AM +1300 On 03/05/16 11:39, Öö Tiib wrote: >> spits the dummy and runs. > The g++ has some sort of variable-length automatic arrays extension > so it somehow weasels out using that on second case I suspect. Good spot, adding -pedantic (almost) does the trick: warning: ISO C++ forbids variable length array 'buf' [-Wvla] char buf[f(8000)]; So you would need both -pedantic and -Werror to catch this case. -- Ian Collins |
David Brown <david.brown@hesbynett.no>: Mar 04 06:58PM +0100 On 04/03/16 18:34, Richard wrote: > question of how would you do things in practice under a constrained > environment where using the heap is out of the question. Avoiding being > "clever" here is probably the best advice. On that last point, I agree entirely - being "clever" is rarely a good plan! Without a heap, classes like vector would be of limited value. However, I could see the use of a map or queue container of some sort (not necessarily the standard library types) with either a fixed constant maximum size, or perhaps with a fixed size given when the structure is allocated on the stack (like a VLA). >> that shared_ptr does [...] > Again -- shared_ptr is for using the heap. Why would you be > attempting to use shared_ptr when you don't want to use the heap? The concept of "smart pointers" can be used for a variety of purposes, not just to track memory. Whenever you have RAII to control a resource, and you might want to access that resource from several contexts (like different RTOS threads), you could have a shared pointer type of management class. But in such cases, you would probably know in advance exactly how many such managers you would want, and be able to have statically allocated data (such as reference counters) for them - you would perhaps want your own specialised sharer class, rather than a shared_ptr. There are also other types of dynamic memory that can be allowed in embedded systems even if a general malloc-style heap is banned. In systems with Ethernet, it is common to have dynamically allocated buffers and other resources - but they would come from specific pools in order to be sure that you have control over allocation/deallocation times, avoid memory fragmentation, and do not end up with low-priority processes using all the memory and leaving nothing for high-priority situations. A standard smart_ptr may be a suitable way of handling such buffers - but only if the pointer's control block can be allocated in a controlled manner rather than on the heap. |
Gareth Owen <gwowen@gmail.com>: Mar 04 06:02PM > int foo[16]; > // fill in values > std::sort(std::begin(foo), std::end(foo)); or, if you're just lazy... int foo[16]; // fill in values std::sort(foo,foo+16); |
scott@slp53.sl.home (Scott Lurndal): Mar 04 06:30PM >>to code footprint >>issues (partially resolved in more modern compilers). >Oh yeah, I remember Cfront on SGIs :-). To be accurate, the cfront project was a Burroughs/Convergent Technologies -> Unisys distributed operating system for a massively parallel system (called OPUS) and development servers were motorola 88100 VME boxes (later Unisys S/8400 88100 boxes) using NCD-16 X-terminals. We were far more concerned with the C compiler used to compile the output of cfront (it was a PCC port to M88100). SGI had a real C++ compiler (and a pretty good one, too). |
Juha Nieminen <nospam@thanks.invalid>: Mar 04 07:28PM > Compiling the Linux kernel with some random perfectly-conforming > C compiler will probably result in a kernel which doesn't actually work. Given that the linux kernel (as most kernels) contains some inline asm, it's not exactly 100% C-standard compliant in the first place... (I don't think a kernel can be implemented with zero inline-asm, at least not for the x86 architecture, assuming the kernel is 32-bit or 64-bit. At the very least you need code to perform a mode switch.) --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Juha Nieminen <nospam@thanks.invalid>: Mar 04 07:35PM > There are no requirements in C++ to use dynamic memory, though it is > often used "behind the scenes" - you have to be careful and know what > you are doing if you want to avoid dynamic memory entirely. I'm not sure in which non-obvious situation a C++ program would use dynamic memory allocation. I don't think even virtual functions (if you wanted to use them for some strange reason) would cause dynamic memory allocation. (AFAIK virtual tables are static, with at most their pointers being set at launch time, if even then.) Sure, if you use the standard containers, dynamic allocations will be made, but that's a no-brainer. (Although there's a way to use them without dynamic allocation, if you really need to. You simply have to implement your own allocator for them, which uses a static buffer.) I'd say there are many things in C that might or might not use dynamic memory allocation, and it's hard to know for sure. For example, does fopen() or fread() use dynamic memory allocation? I have no idea. (I think that these may be needed even in small embedded environments in some cases.) --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
David Brown <david.brown@hesbynett.no>: Mar 04 08:50PM +0100 On 04/03/16 20:35, Juha Nieminen wrote: > example, does fopen() or fread() use dynamic memory allocation? > I have no idea. (I think that these may be needed even in small > embedded environments in some cases.) I think you would rarely need such functions in an embedded system that is too constrained (in resources or timing requirements) to have a heap. But your point is perfectly valid - C functions may use heap memory without making it clear, just like C++ functions or classes. |
scott@slp53.sl.home (Scott Lurndal): Mar 04 08:04PM >(I don't think a kernel can be implemented with zero inline-asm, at >least not for the x86 architecture, assuming the kernel is 32-bit or >64-bit. At the very least you need code to perform a mode switch.) GCC already has various __builtin functions that can be used to generate specific assembly (__builtin_popcount is one I use heavily). Other high-level languages I've used for OS development implemented similar intrinsic functions (e.g. ALGOL for Burroughs Large Systems, SPRITE for Burroughs medium systems, SPL for HP-3000's, BLISS-32 on Digital systems, et alia) to generate specific instructions. Burroughs medium systems COBOL68 compiler had a statement called 'ENTER SYMBOLIC' that allowed inline assembler in COBOL programs. There was no assembler offered to customers with either of the Medium or Large systems mainframe lines and COBOL74 removed the ability to ENTER SYMBOLIC. |
scott@slp53.sl.home (Scott Lurndal): Mar 04 08:06PM >example, does fopen() or fread() use dynamic memory allocation? >I have no idea. (I think that these may be needed even in small >embedded environments in some cases.) In our C++ hypervisor, we did this: /* * This is called by setup64.S to call the constructors of global objects, * before it calls dvmm_bsp_start(). * * GNU LD lays out the __CTOR_LIST__ as an array of function pointers. The * first element of the array (index == 0) contains an integer which * represents the value derived from subtracting two from the actual number * of entries in the table. Thus the content of the first element is * one less than the index of the last entry in the table. * * Call in reverse order XXX - why? Check crt0.o for canonical behavior */ extern "C" void __call_constructors() { size_t count = *(size_t *)__CTOR_LIST__; for(count++; count; --count) { __CTOR_LIST__[count](); } } /* * G++'s generated code calls this if a pure virtual member is ever called. */ extern "C" void __cxa_pure_virtual() { panic("pure virtual function called\n"); } /* * This is needed even though we don't ever use the delete operator because * G++ generates an extra (unused) virtual destructor that calls it. */ void operator delete(void *) { panic("operator delete(void*) called\n"); } /* * Catch unintended calls to new. */ void* operator new(size_t) { panic("operator new(void*) called\n"); } |
Wouter van Ooijen <wouter@voti.nl>: Mar 04 09:27PM +0100 Op 04-Mar-16 om 6:31 PM schreef Richard: > I'm talking about his point about avoiding dynamic memory allocation. > Functors and exceptions don't have to do with dynamic memory > allocation unless you start writing calls to new yourself. IME that is not true. The exception handling 'framework' that is added when you use exception does use the heap, as does std::function. (snip) >> requirement that sin() doesn't use the heap. > Sorry, this is either a pointless exercise in pedantry or it is a > straw man argument. Why? The point is that without trying I can make an educated guess what kind of library elements do or don't use any of (heap, exception, RTTI), but I can't be sure. Wouter |
Ian Collins <ian-news@hotmail.com>: Mar 05 09:34AM +1300 On 03/05/16 04:41, Richard wrote: > I assume you are referring to containers when you say "STL". > I can't see why the algorithms wouldn't be useful in a constrained > environment. I did suggest on the low traffic comp.std.c++ group that standard library headers that don't require run time (especially dynamic allocation) support should be identified in the standard. One of these days I'll follow this up. -- Ian Collins |
legalize+jeeves@mail.xmission.com (Richard): Mar 04 09:57PM [Please do not mail me a copy of your followup] Gareth Owen <gwowen@gmail.com> spake the secret code >int foo[16]; >// fill in values >std::sort(foo,foo+16); Good point. I wouldn't say you even have to be lazy :-). The form with begin/end doesn't need to be updated if the number of elements in the array change later-on. Having to make the same change (16 to 20 for instance) in multiple places in the code is a code smell. The std::begin/end usefulness for fixed length C style arrays comes in most handy with a range for statement. -- "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): Mar 04 09:58PM [Please do not mail me a copy of your followup] slp53@pacbell.net spake the secret code >SGI had a real C++ compiler (and a pretty good one, too). Only after they had a Cfront based compiler. I know because I was using their compiler at the point when they switched. -- "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> |
Juha Nieminen <nospam@thanks.invalid>: Mar 04 07:24PM > You can swap two std::vector instances and keep item references valid. Fair enough. That's probably the only requirement that would be broken with a "small vector optimization". --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
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