- Why should a "c" programmer learn c++ ? (V2) - 8 Updates
- Why should a "c" programmer learn c++ ? - 4 Updates
- problem with std::string::c_str() - 7 Updates
- "C++ Creator Bjarne Stroustrup Weighs in on Distributed Systems, Type Safety and Rust" - 1 Update
- Why halt deciders can't be "interesting" programs. (H is bad?) - 3 Updates
- cannot find C++ regex tester - 1 Update
- Change (USA Reprise) - 1 Update
Juha Nieminen <nospam@thanks.invalid>: Sep 12 05:49AM >> legally right thing. > They are giving people in those areas a US$6000 incentive to lobby for > law changes. Punishing people who have done nothing wrong is not the right way to go. The only thing that it causes is for people to "pirate" the software, technically speaking, under the assumption that the sqlite team will never sue them. |
"Öö Tiib" <ootiib@hot.ee>: Sep 12 12:16AM -0700 On Friday, 11 September 2020 20:08:50 UTC+3, Juha Nieminen wrote: > publish works into the public domain, why do they want to punish the > people living in those places who have done nothing wrong? It's not > their fault. As there are no monarchs whom to punish. The laws are what people made these to be. |
David Brown <david.brown@hesbynett.no>: Sep 12 01:50PM +0200 On 12/09/2020 00:20, Joe Pfeiffer wrote: >> that way since before the Internet boom. I refer you to "What To Do >> When the Trisector Comes" by Underwood Dudley. > I hadn't come across that little article before. Thanks, it was fun. Yes, indeed. Sometimes small gems come out of even the most useless threads! |
Anton Shepelev <anton.txt@gmail.com>: Sep 12 03:51PM +0300 olcott: > I spoke with someone on the comp.lang.c recently about the > benefits of c++. Her objections was that c++ has a huge > learning curve. It is inevitable for such a multi-paradigm moster of a language. One need only compare the relative thickness of books describing C and C++. There is a fundamental argument for the simplicity of a language. It appeals to the universal criterium of perfection, which is also the basis of the unviverse, -- the supremacy of the whole over the sum of its parts. A complex system is beautiful when built with a small number of simle building blocks and ugly when built with a large nubmer of building blocks of which some are more complex than the system itself. > I have been a "c" programmer since K&R was the official > standard -> You had better had been C programmer. A "c" programmer reads like a disparaging parody on the former term. > make programming much easier. In two decades as a c++ > programmer I don't hardly use anything else besides those > three things. A approve of this approach, if one must use C++ at all. I myself program in C#, but employ a very limited set of its features. As far as I know, C++ began as a light-weight preprocessing wrapper around plain C that added one thing only: classes. It therefore did not even have a dedicated compliler, relying on existing C compilers, and wasn't that convenient? I can understnand why that language was called C++ -- a small addition to C. Now it something else. This feature-ascetism, however, has the downside that other programmers will have their own opinions about which features are useful, and will make fun of you for using 1% instead of, say, 4% of C++. That may be a problem if you work in a team. A colleague of mine told me a horror story about his friend who did not pass an interview for a C++ programming job because he employed normal iteration instead of some funcional-based and query-like facility where it was obviously not needed. The employer wanted an over-engineered solution the easier to adapt it to hypothetical new requirements in the hypothetical future. > C++ classes implement the key most important and useful > aspect of Object Oriented Programming (OOP). I have never > found any other aspect of OOP useful. What other aspects are there? Well, I have never found any aspect of OOP useful, anyway. Heavy use of classes dictates a totally different program structure. While they are not very difficult to understand, the way of thinking required to design good object-oriented software is radically different and takes a long time to acquire, if at all. But if one must have OOP, one need not append ++ to C. Axel- Tobias Schreiner describes an OO-framework for plain C in his book "Object-oriented programming in C": https://www.cs.rit.edu/~ats/books/ooc.pdf > functions that operate only on this data. Code and data > can be kept together in the same place eliminating the > possibility of data dependency side-effects. I consider this a fault rather than advantage: data and operations belong in different domains and shall not be mixed. This is so fundamental a principle that Niclaus Wirth put it in the title of his book: Algorithhms + Data structures = Programs > With OOP you can create self-contained units of > modularity. This is ht e greatest thing about c++ and OOP. It is ironical that a C++ programmer should talk about modularity. Header files are a parody of modules. Whereas true modules have been added to C++ no so long ago, they had been available way before OOP in such langugages as ALGOL and Modula. > The std::vector array always knows its current size: > size() and you can append another element with memory > management automatically handled for you with push_back(). C can do abstract dynamic arrays with exponential memory allocation that are transparent and substitutable for normal C arrays. I have implemented such dymamic arrays as a C "module", with the help of several members of CLC. The example below creates a dymamic array, adds elelements to it in three different ways, and prints the contents: #include <stdio.h> #include <stdlib.h> #include <string.h> #include "dynarray.h" /* ... */ int *a, v, i, l; /* arrary, value, index, length */ void* vP; /* poiter to array value */ da_new ( &a, sizeof( int ) ); /* create new array */ da_setlen( &a, 2 ); /* set a length of 2 */ a[0] = 0; a[1] = 1; da_setlen( &a, 4 ); /* set a length of 4 */ a[2] = 2; a[3] = 3; v = 4; da_add( &a, &v ); /* add element with value */ v = 5; da_addemp( &a, &vP ); /* add an empty element and */ memcpy( vP, &v, sizeof( int ) ); /* fill it */ l = da_len( &a ); /* read the length */ for( i = 0; i < l; i++ ) { printf("%i ", a[i]); } da_free( &a ); Observe that my dynamic arrays are declared as normal C arrays, and their elements are read and assigned to exactly as if they were a normal C arrays. Error handling is omitted for simplicity, but pray do not mentioned exceptions. > The allocation algorithm is an optimal balance between > time and space can be easily superseded with resize() or > reserve(). Interesting. Is it a grow-only or grow-and-shrink algorithm? Can you delineate it for me if will not take more that three paragraphs, or refer me to a description? In my dynamic arrays, the da_setlen() function performes the office of reserve(): in addition to setting the exact length, it makes sure that enough memory is allocated. > std::string is a string of characters that can grow as > large as needed and has the same interface as std::vector. The lack of a string type is a deficiency in C, but one can be implemented, for example on top of my dynamic arrays. I will not take the banana of std::string if the entire jungle of C++ has to come with it. -- () ascii ribbon campaign -- against html e-mail /\ http://preview.tinyurl.com/qcy6mjc [archived] |
olcott <NoOne@NoWhere.com>: Sep 12 08:46AM -0500 On 9/12/2020 7:51 AM, Anton Shepelev wrote: >> aspect of Object Oriented Programming (OOP). I have never >> found any other aspect of OOP useful. > What other aspects are there? Well, I have never found any Inhertance. > very difficult to understand, the way of thinking required > to design good object-oriented software is radically > different and takes a long time to acquire, if at all. It was very natural for me. We just added containment to top down design. > operations belong in different domains and shall not be > mixed. This is so fundamental a principle that Niclaus Wirth > put it in the title of his book: Without containment we have side-effects. > true modules have been added to C++ no so long ago, they had > been available way before OOP in such langugages as ALGOL > and Modula. I just wrote a whole COFF object file library as a single header file. > "module", with the help of several members of CLC. The > example below creates a dymamic array, adds elelements to it > in three different ways, and prints the contents: Without templates its clumsier to create an array of anything. >> time and space can be easily superseded with resize() or >> reserve(). > Interesting. Is it a grow-only or grow-and-shrink algorithm? It enlarges the memory allocation by a factor of 1.5 to 2.0 and copies all the elements whenever totally memory is used up. It does this automatically on std::vector::push_back(); Or you can allocate enough memory in advance with reserve() or resize(). With resize you can just use it like an array with subscripts. If you index out-of-bounds it crashes. With reserve() adding an element requires push_back() yet it is much faster because the memory is already allocated. You use std::vector::size() to always know the current boundary. > be implemented, for example on top of my dynamic arrays. I > will not take the banana of std::string if the entire jungle > of C++ has to come with it. I have hardly every used any aspect of C++ (in my own code) besides the above three things in two decades as a C++ programmer. std::vector is the only way I ever use dynamically allocated memory. -- Copyright 2020 Pete Olcott |
Anton Shepelev <anton.txt@gmail.com>: Sep 12 05:50PM +0300 olcott to Anton Shepelev: > > > have never found any other aspect of OOP useful. > > What other aspects are there? > Inhertance. I thought classes had inheritance by definition; they would not be classes otherwise. So you use classes with methods but without inheritcance? -- interesting. > > mixed. This is so fundamental a principle that Niclaus > > Wirth put it in the title of his book: > Without containment we have side-effects. I beg pardon for overlooking your mention of side effects the first time. I don't understand what side effects are inevitable in procedural programming that classes help to avoid. Speaking of modules and modularity: > I just wrote a whole COFF object file library as a single > header file. Is it not an abuse of headers? Can it be considered modular design if the header is simply pasted into code by the macro processor, has no separation of interface and implementation, and cannot be compiled separattely? > Without templates its clumsier to create an array of > anything. You surely mean a dynamic array. In my previous post I have shown how a universal dynamic array can be implemented in C. About the memory management in std:vector: > 2.0 and copies all the elements whenever totally memory is > used up. It does this automatically on > std::vector::push_back(); So do my C dynamic arrays, although the factor is constant. > reserve() or resize(). With resize you can just use it > like an array with subscripts. If you index out-of-bounds > it crashes. So do my C dynamic arrays, where you can set capacity and actual length. > it is much faster because the memory is already allocated. > You use std::vector::size() to always know the current > boundary. It is very simlar with my dynamic arrays in C. > std::vector is the only way I ever use dynamically > allocated memory. Indeed. Anything else is hardly needed for most applications. -- () ascii ribbon campaign -- against html e-mail /\ http://preview.tinyurl.com/qcy6mjc [archived] |
olcott <NoOne@NoWhere.com>: Sep 12 10:30AM -0500 On 9/12/2020 9:50 AM, Anton Shepelev wrote: > I thought classes had inheritance by definition; they would > not be classes otherwise. So you use classes with methods > but without inheritcance? -- interesting. http://wiki.c2.com/?InheritanceBreaksEncapsulation > the first time. I don't understand what side effects are > inevitable in procedural programming that classes help to > avoid. If every function depends on the same global data pool changes to one function can break other functions. >> anything. > You surely mean a dynamic array. In my previous post I have > shown how a universal dynamic array can be implemented in C. I did not pay much attention because std::vector is already perfect. >> used up. It does this automatically on >> std::vector::push_back(); > So do my C dynamic arrays, although the factor is constant. With a constant growth size is prioritized over time. >> allocated memory. > Indeed. Anything else is hardly needed for most > applications. In other words I never ever use new, malloc() or calloc(). I did try using std::list once yet the benchmarks proved that std::vector is much more efficient even for most linked list things. -- Copyright 2020 Pete Olcott |
Bonita Montero <Bonita.Montero@gmail.com>: Sep 12 08:10PM +0200 > I did not pay much attention because std::vector is already perfect. I derived a class gvector. It has a growth-factor of n and m. n is an integral growth-factor that the vector's capacity is lineary incremented every time it gets full. m is a float that the vector's capacity is mul- tiplied by if it gets full. Whichever size is chosen depends on which is greater. Usually n is chosen that it determines the allocation-steps which are backed by the memory-pool of the allocator. When the memory-allocator begin to allocate the memory directly from the kernel as the block-size gets large enough, the capacity is resized by an appropriately chosen m. One might think that multiplying the vector's capacity by a constant factor is a waste of memory, but keep in mind that the kernels don't really physically allocate pages demanded from the kernel until you really touch the memory; and memory that is only allocated to reserve for a certain capacity isn't touched until you add elements to the vector. So here's my gvector: #pragma once #include <vector> #include <utility> #include <new> #include <cassert> template<typename T, typename Allocator = std::allocator<T>> struct gvector : public std::vector<T, Allocator> { using super = std::vector<T, Allocator>; using iterator = typename super::iterator; using const_iterator = typename super::const_iterator; using size_type = typename super::size_type; explicit gvector( std::size_t growConst = 1, float growExp = 1.0, Allocator const &alloc = Allocator() ); explicit gvector( Allocator const &alloc = Allocator() ); explicit gvector( size_type count, T const &value, Allocator const &alloc = Allocator() ); explicit gvector( size_type count ); template<typename InputIt> gvector( InputIt first, InputIt last, Allocator const &alloc = Allocator() ); gvector( super const &other ); gvector( super const &other, Allocator const &alloc = Allocator() ); gvector( super const &&other ); gvector( std::initializer_list<T> init, Allocator const &alloc = Allocator() ); iterator insert( iterator pos, T const &value ); iterator insert( const_iterator pos, T const &value ); iterator insert( const_iterator pos, T const &&value ); iterator insert( const_iterator pos, size_type count, T const &value ); template<typename InputIt> iterator insert( const_iterator pos, InputIt first, InputIt last ); iterator insert( const_iterator pos, std::initializer_list<T> ilist ); template<typename ... Args> iterator emplace( const_iterator pos, Args &&...args ); void push_back( T const &value ); void push_back( T &&value ); template<typename ... Args> void emplace_back( Args &&...args ); void set_grow( std::size_t growConst = 1, float growExp = 1.0 ); private: void grow(); std::size_t m_growConst; float m_growExp; }; template<typename T, typename Allocator> gvector<T, Allocator>::gvector( std::size_t growConst, float growExp, Allocator const &alloc ) : super( alloc ), m_growConst( growConst ), m_growExp( growExp ) { assert(growExp >= 0.0); } template<typename T, typename Allocator> inline gvector<T, Allocator>::gvector::gvector( Allocator const &alloc ) : super( alloc ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> inline gvector<T, Allocator>::gvector::gvector( size_type count, T const &value, Allocator const &alloc ) : super( count, value, alloc ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> inline gvector<T, Allocator>::gvector::gvector( size_type count ) : super( count ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> template<typename InputIt> inline gvector<T, Allocator>::gvector::gvector( InputIt first, InputIt last, Allocator const &alloc ) : super( first, last, alloc ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> inline gvector<T, Allocator>::gvector::gvector( super const &other ) : super( other ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> inline gvector<T, Allocator>::gvector::gvector( super const &other, Allocator const &alloc ) : super( other, alloc ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> inline gvector<T, Allocator>::gvector::gvector( super const &&other ) : super( std::move( other ) ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> inline gvector<T, Allocator>::gvector::gvector( std::initializer_list<T> init, Allocator const &alloc ) : super( init, alloc ), m_growConst( 1 ), m_growExp( 0.0 ) { } template<typename T, typename Allocator> inline typename gvector<T, Allocator>::iterator gvector<T, Allocator>::insert( iterator pos, T const &value ) { if( super::size() == super::capacity() ) grow(); return super::insert( pos, value ); } template<typename T, typename Allocator> inline typename gvector<T, Allocator>::iterator gvector<T, Allocator>::insert( const_iterator pos, T const &value ) { if( super::size() == super::capacity() ) grow(); return super::insert( pos, value ); } template<typename T, typename Allocator> inline typename gvector<T, Allocator>::iterator gvector<T, Allocator>::insert( const_iterator pos, T const &&value ) { if( super::size() == super::capacity() ) grow(); return super::insert( pos, value ); } template<typename T, typename Allocator> inline typename gvector<T, Allocator>::iterator gvector<T, Allocator>::insert( const_iterator pos, size_type count, T const &value ) { if( super::size() == super::capacity() ) grow(); return super::insert( pos, count, value ); } template<typename T, typename Allocator> template<typename InputIt> inline typename gvector<T, Allocator>::iterator gvector<T, Allocator>::insert( const_iterator pos, InputIt first, InputIt last ) { if( super::size() == super::capacity() ) grow(); return super::insert( pos, first, last ); } template<typename T, typename Allocator> inline typename gvector<T, Allocator>::iterator gvector<T, Allocator>::insert( const_iterator pos, std::initializer_list<T> ilist ) { if( super::size() == super::capacity() ) grow(); return super::insert( pos, ilist ); } template<typename T, typename Allocator> template<typename ... Args> inline typename gvector<T, Allocator>::iterator gvector<T, Allocator>::emplace( const_iterator pos, Args &&...args ) { if( super::size() == super::capacity() ) grow(); return super::emplace( pos, args ... ); } template<typename T, typename Allocator> inline void gvector<T, Allocator>::push_back( T const &value ) { if( super::size() == super::capacity() ) grow(); super::push_back( value ); } template<typename T, typename Allocator> inline void gvector<T, Allocator>::push_back( T &&value ) { if( super::size() == super::capacity() ) grow(); super::push_back( std::move( value ) ); } template<typename T, typename Allocator> template<typename ... Args> inline void gvector<T, Allocator>::emplace_back( Args &&...args ) { if( super::size() == super::capacity() ) grow(); super::emplace_back( args ... ); } template<typename T, typename Allocator> void gvector<T, Allocator>::set_grow( std::size_t growConst, float growExp ) { assert(growExp >= 0.0); m_growConst = growConst; m_growExp = growExp; } template<typename T, typename Allocator> void gvector<T, Allocator>::grow() { using namespace std; size_t size = super::size(), capacity = super::capacity(); assert(size == capacity); size_t growConst = size + m_growConst, growExp = (size_t)(size * m_growExp); growExp = growExp != size ? growExp : size + 1; try { super::reserve( growConst >= growExp ? growConst : growExp ); } catch( bad_alloc & ) { if( growConst >= growExp ) super::reserve( size + 1 ); else try { super::reserve( growConst ); } catch( bad_alloc & ) { super::reserve( size + 1 ); } } } #if !defined(NDEBUG) template struct gvector<char, std::allocator<char>>;
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment