- Struggling with bind syntax - 6 Updates
- braced-init-list form of a condition - 7 Updates
- direct-initialization - 2 Updates
- braced-init-list form of a condition - 1 Update
- Checking if a linked list is circular with smart pointers - 2 Updates
- About virtual inheritance - 5 Updates
- Design flaws (Scott..) - 2 Updates
Paul <pepstein5@gmail.com>: Jun 30 10:18AM -0700 I am trying to write two versions of Quicksort, one that uses randomised partition, and one that doesn't randomise the partition. However, I want them to have signatures std::vector<int> f(std::vector<int> vec) and so I want to bind the quicksorts to Boolean parameters. I can't find the syntax to do this though. Just so that I haven't left out any context, I will copy-paste my entire code. However, I will mark out the offending line with asterisks. Many thanks for your help. #include <vector> #include <cstdlib> #include <cstdio> #include <stdexcept> #include <functional> // Basic swapping useful for many sorts. void Swap(int& x, int& y) { int temp = x; x = y; y = temp; } // Creating a random integer array of size N. // Integers are randomly chosen between 0 and randmax. std::vector<int> CreateRandomArray(int N) { std::vector<int> data; for(int i = 0; i < N; ++i) data.push_back(rand()); return data; } // Testing our sorts by checking that every vector is sorted. // True if sorted. bool TestSort(const std::vector<int>& vec) { if(vec.empty()) return true; for(int i = 0; i < vec.size() - 1; ++i) if(vec[i] > vec[i + 1] ) return false; return true; } // Testing a sort -- generalised for any function of the required type bool TestSortGeneral( std::vector<int> (*const & f)(std::vector<int>), int length) { return TestSort(f(CreateRandomArray(length))); } // Testing a collection of sorts void TestSortCollection(std::vector<std::vector<int>(*) (std::vector<int>) > sortTypes, int length) { for(auto& alg : sortTypes) printf(TestSortGeneral(alg, length) ? "Results as expected\n" : "Problem with sort\n"); } std::vector<int> InsertionSort(std::vector<int> vec) { for(int i = 1; i < vec.size(); ++i) { // Vector is sorted up to i - 1. int j = i - 1; int key = vec[i]; while(j >= 0 && key < vec[j]) { vec[j + 1] = vec[j]; --j; } vec[j + 1] = key; } return vec; } std::vector<int> BubbleSort(std::vector<int> vec) { if(vec.empty()) return vec; const int j = vec.size()-1; bool sorted; do { sorted = true; for(int i = 0; i != j; ++i) if(vec[i] > vec[i + 1]) { Swap(vec[i], vec[i + 1]); sorted = false; } } while(!sorted); return vec; } std::vector<int> SelectionSort(std::vector<int> vec) { for(int i = 0; i < vec.size(); ++i) { int minIndex = i; for(int j = i+1; j < vec.size(); ++j) if(vec[j] < vec[minIndex]) minIndex = j; Swap(vec[i], vec[minIndex]); } return vec; } // Randomly selecting a number in [0 n) int nrand(int n) { if(n <= RAND_MAX) { const int bucket_size = RAND_MAX / n; int r; do r = rand() / bucket_size; while (r >= n); return r; } const int buckets = n / RAND_MAX; const int rem = n % RAND_MAX; // n has been divided into several buckets of RAND_MAX and also a smaller bucket. // We simulate the condition that the random trial landed in the smaller bucket. // By recursion we can assume nrand is defined for all smaller n. // nrand(buckets + 1) == buckets indicates falling off the end. // Once we've fallen off the end, we hit the small bucket if nrand is small enough. const int positionWithinBucket = nrand(RAND_MAX); // Bucket can be either normal bucket or smaller bucket. const int finalBucket = nrand(buckets + 1); const bool smallerBucket = finalBucket == buckets && positionWithinBucket < rem; // If not a small bucket, the process is straightforward. Randomly select the large bucket and use the position within the bucket. const int bucketIndex = smallerBucket ? buckets : nrand(buckets); return bucketIndex * RAND_MAX + positionWithinBucket; } // Index for such that left-of-index members are smaller than right-of-index members // Call by pointer to preserve sort. // bool random indicates whether partitioning is random int QuickSortPartition(std::vector<int>* vec, bool random = false) { if(vec->empty()) throw std::runtime_error("Should not be called on an empty vector"); const int j = vec->size() - 1; if(random) Swap((*vec)[j], (*vec)[nrand(j)]); int& key = (*vec)[j]; int lowIndex = 0; for(int i = 0; i < j; ++i) if((*vec)[i] < key) Swap((*vec)[lowIndex++], (*vec)[i]); Swap(key, (*vec)[lowIndex]); return lowIndex; } std::vector<int> QuickSort(std::vector<int> vec, bool random = false) { if(vec.size() <= 1) return vec; int index = QuickSortPartition(&vec, random); std::vector<int> left; std::vector<int> right; std::vector<int> results; for(int i = 0; i < index; ++i) left.push_back(vec[i]); for(int i = index + 1; i < vec.size(); ++i) right.push_back(vec[i]); left = QuickSort(left, random); left.push_back(vec[index]); right = QuickSort(right, random); results = left; for(auto i : right) results.push_back(i); return results; } // Use bind concept to distinguish the two types of Quicksort without repeating code. /***************************************************************************************************** Below is meant to declare the variant of QuickSort that uses bool random = false but I can't find the syntax. ************************************************************************************************************ ************************************************************************************************************* Below line gives compile error! */ std::vector<int>(*QuickSortBasic)(std::vector<int>) = std::bind(QuickSort, std::placeholders::_2, false); // N is the length of each vector void CombinedTest(int N) { std::vector<std::vector<int>(*) (std::vector<int>) > sortTypes; sortTypes.push_back(InsertionSort); sortTypes.push_back(BubbleSort); sortTypes.push_back(SelectionSort); sortTypes.push_back(QuickSortBasic); TestSortCollection(sortTypes, N); } int main() { const int vecLength = 50 * 1000; CombinedTest(vecLength); return 0; } |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 30 08:56PM +0200 On 30-Jun-15 7:18 PM, Paul wrote: > I am trying to write two versions of Quicksort, one that uses randomised partition, and one that doesn't randomise the partition. However, I want them to have signatures std::vector<int> f(std::vector<int> vec) and so I want to bind the quicksorts to Boolean parameters. > I can't find the syntax to do this though. Just so that I haven't left out any context, I will copy-paste my entire code. However, I will mark out the offending line with asterisks. > Many thanks for your help. Instead of std::bind I'd just use lambdas. They're good at binding and work as expected. In contrast, std::bind only works as expected by chance. Cheers & hth., - Alf -- Using Thunderbird as Usenet client, Eternal September as NNTP server. |
JiiPee <no@notvalid.com>: Jun 30 09:01PM +0100 On 30/06/2015 19:56, Alf P. Steinbach wrote: > chance. > Cheers & hth., > - Alf niin se Scottkin sanoi... etta "hyva jos et ole oppinut bindia" :)... minahan en ole sita opetetllut, eli kaytan suoraan lambdoja |
guinness.tony@gmail.com: Jun 30 02:05PM -0700 On Tuesday, 30 June 2015 18:19:11 UTC+1, Paul wrote: > I am trying to write two versions of Quicksort, one that uses randomised partition, and one that doesn't randomise the partition. However, I want them to have signatures std::vector<int> f(std::vector<int> vec) and so I want to bind the quicksorts to Boolean parameters. > I can't find the syntax to do this though. Just so that I haven't left out any context, I will copy-paste my entire code. However, I will mark out the offending line with asterisks. > Many thanks for your help. <snip> std::vector<int> QuickSort(std::vector<int> vec, bool random = false) > { <snip> > ************************************************************************************************************* > Below line gives compile error! */ > std::vector<int>(*QuickSortBasic)(std::vector<int>) = std::bind(QuickSort, std::placeholders::_2, false); <snip> std::bind() returns an object encapsulating enough information to call your QuickSort function with the correct set of parameters when it is "called" (i.e. it passes the parameter passed in the call and the parameter given to std::bind()). As such, it is a functional object (a "functor") and definitely not a function pointer. Furthermore, the Standard tells us that the type of that object is unspecified, so you cannot write its type out in your declaration of QuickSortBasic. So just use auto QuickSortBasic = std::bind(QuickSort, std::placeholders::_2, false); instead, which is so much neater anyway. If you *really* want to avoid using 'auto' and spell out the type of the binder object, you'll need to resort to using the deprecated bind2nd() binder, thus: std::binder2nd< std::pointer_to_binary_function< std::vector<int>, bool, std::vector<int> > > QuickSortBasic = std::bind2nd(std::ptr_fun(QuickSort), false); However, apart from the issue of these binders being deprecated, I'm sure you'll agree that this is a particularly ugly solution. Like the rest of us, be thankful for 'auto' and std::bind(). |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 30 10:27PM +0100 > If you *really* want to avoid using 'auto' and spell out the type > of the binder object, you'll need to resort to using the deprecated > bind2nd() binder, thus: Nonsense, just store the result of std::bind in a std::function object. [snip] /Flibble |
guinness.tony@gmail.com: Jun 30 03:26PM -0700 On Tuesday, 30 June 2015 22:27:53 UTC+1, Mr Flibble wrote: > Nonsense, just store the result of std::bind in a std::function object. > [snip] > /Flibble Well, yes - there are conversions from the unspecified return type from std::bind to an appropriate specialisation of std::function. Whilst trying to get that specialisation right, I noticed that the OP also passes the wrong placeholder into the std::bind() argument list. So, for the OP, you /could/ spell out a type to hold *a conversion from* the result of std::bind(): std::function<std::vector<int>(std::vector<int>)> BasicQuickSort = std::bind(QuickSort, std::placeholders::_1, false); But I would still use 'auto'. |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 08:16PM There is a specification for C++ that contains this noun phrase: braced-init-list form of a condition in 8.5p16. What does this refer to? Could it refer to if( bool b{ true }) ... ? |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 08:31PM 5.5p16 says: The initialization that occurs in the forms T x(a); T x{a}; (...) is called direct-initialization. (End of quotation). Is »a« a single expression above? So, ::std::string s( 3, 'c' ); is not a direct-initialization because there is not a single expression in the parentheses? If this is true, what kind of initialization is it? |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 08:45PM >I think the 'condition' requires an equal sign if it's a declaration of >a variable. The equals sign is not required. I quote 6.4p1: selection-statement: if ( condition ) statement (...) condition: attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list . |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 08:52PM >>a variable. >The equals sign is not required. I quote 6.4p1: >condition: Of course, the English meaning of »condition« is something else. My course participants heavily protested when I #include <cstdio> int main() { if( ::std::puts( "hello, world" )){} } , and I just wanted to show that you can program without the semicolon »;«! |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 09:07PM >>5.5p16 says: >Really? The paragraph 5.5/16 doesn't exist in the document I use. Did >you mean 8.5/16? Yes. Sorry, that was a typo! >It is direct. See just lower, "If the destination type is a .. class type:" The parapraph 17 seems just intended to give the semantics once the kind of initialization syntax is already determined. |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 09:41PM >>T x(a); >>Is »a« a single expression above? >Most likely. I hope not. And I found some evidence in an old standard for C++ from the year 1998. There in it is written: »is called direct-initialization and is equivalent to the form T x(a);«, 1998:8.5p12. »When objects of class type are direct-initialized ... The argument list is the expression-list within the parentheses of the initializer.«, 1998:13.3.1.3p1. So 1998:13.3.1.3 says »expression-list«! The recent 13.3.1.3 also uses »expression-list« but it is less clear since it also refers to other kinds of initializations, while 1998:13.3.1.3 only referred to direct-initialization. |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 10:16PM >or > T x{a}; >in which 'a' does *not* have to be a single expression (see p13). That quotation from above did not explictly refer to direct-initializations only AFAIK. It is possible that the form T x( a, b ) is also an initialization, but not a direct-initialization (it is possible that it is neither a copy-initialization nor a direct-initialization, but just »an initialization«). The quotation than could refer to this. |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 30 04:52PM -0400 On 6/30/2015 4:31 PM, Stefan Ram wrote: > 5.5p16 says: Really? The paragraph 5.5/16 doesn't exist in the document I use. Did you mean 8.5/16? > (...) is called direct-initialization. > (End of quotation). > Is »a« a single expression above? Most likely. It's written as an opposite form of the T x = a; described in the preceding paragraph, and relates to the paragraph that starts with "The form of initialization". They are talking of a single expression there. > is not a direct-initialization because there > is not a single expression in the parentheses? > If this is true, what kind of initialization is it? It is direct. See just lower, "If the destination type is a .. class type:" V -- I do not respond to top-posted replies, please don't ask |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 30 05:57PM -0400 On 6/30/2015 5:07 PM, Stefan Ram wrote: >> It is direct. See just lower, "If the destination type is a .. class type:" > The parapraph 17 seems just intended to give the semantics > once the kind of initialization syntax is already determined. "If the entity being initialized does not have class type, the expression-list in a parenthesized initializer shall be a single expression." From p16 I conclude that in a class type the direct initialization can take the form T x(a); or T x{a}; in which 'a' does *not* have to be a single expression (see p13). V -- I do not respond to top-posted replies, please don't ask |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 30 04:38PM -0400 On 6/30/2015 4:16 PM, Stefan Ram wrote: > Could it refer to > if( bool b{ true }) ... > ? I think the 'condition' requires an equal sign if it's a declaration of a variable. IOW, it could be if (bool b = {true}) Of course it makes more sense with a class that has a conversion to bool defined for it and has a c-tor to initialize it from a list, so you can write class MySpecialClass { public: MySpecialClass(std::initializer_list<int> list); operator bool() const; }; int main() { if (MySpecialClass obj = { 42, 666 }) return 0; } V -- I do not respond to top-posted replies, please don't ask |
Paul <pepstein5@gmail.com>: Jun 30 10:20AM -0700 On Sunday, June 28, 2015 at 4:40:19 PM UTC+1, Öö Tiib wrote: > whole list. You should perhaps try and compare the two with list of > million of entries. > Your 'smallTests' is still broken in sense that it leaks memory. Yes, I did understand your advice but some companies seem a bit dogmatic about always using smart pointers and I'm trying to learn to please them. Thanks to all who have taken the time to help me. Paul |
Christopher Pisz <nospam@notanaddress.com>: Jun 30 01:40PM -0500 On 6/30/2015 12:20 PM, Paul wrote: > Yes, I did understand your advice but some companies seem a bit dogmatic about always using smart pointers and I'm trying to learn to please them. > Thanks to all who have taken the time to help me. > Paul "Always use smart pointers" is an ignorant rule and their bug trackers will show it. Use raw pointers when it makes sense to use raw pointers. Use shared_ptr when it makes sense to use shared_ptr. Use weak_ptr when it makes sense to use weak_ptr. Use unique_ptr when it makes sense to use unique_ptr. Those companies are going to spend just as much, if not more, man hours debugging "why didn't X get released" and circular references, as they will from people using raw pointers poorly. It's always some guy that thinks, it is a good idea to use shared_ptrs like a C# garbage collector. -- I have chosen to troll filter/ignore all subthreads containing the words: "Rick C. Hodgins", "Flibble", and "Islam" So, I won't be able to see or respond to any such messages --- |
Richard Damon <Richard@Damon-Family.org>: Jun 29 09:56PM -0400 On 6/29/15 12:39 PM, Öö Tiib wrote: > Uhh? What these Base, 'Der1', 'Der2' and 'Join' are? I don't have those > anywhere. However ... I have just learned it for case that maybe > someday I meet a case where something somewhere needs that. Here is an example. Assume we are designing a fantasy game, and one of the objects we want to be able to represent are creatures, which hold a number of attributes common to all creatures (like life level). There also exist some special types of creatures that need extra attributes and are represented as derived classes (For example, Dragons with flying and breath weapons, and Warriors with weapon skills). We may then want a creature that belongs to multiple of these special classes, so we want to multiply inherent from each of the specialty classes so it collects all of the special properties, in this case a Dragon Warrior (Yikes). Without using virtual bases, the Dragon warrior is two creature, each with their own sets of properties. Thus if I damage it as a Dragon, that damage doesn't affect the Warrior. This isn't right! We want all creatures to only have creature class within them, so we make it a virtual base. The key is looking to see if you are going to get to the multiple inheritance case with (a) common base(s). And if you do, should there be just a single copy of that base shared by the whole object, or does each path to it need their own distinct copy. |
"Öö Tiib" <ootiib@hot.ee>: Jun 30 06:18AM -0700 On Tuesday, 30 June 2015 04:56:37 UTC+3, Richard Damon wrote: > creature that belongs to multiple of these special classes, so we want > to multiply inherent from each of the specialty classes so it collects > all of the special properties, in this case a Dragon Warrior (Yikes). Yikes? :) Feels that you think yourself that something is wrong with it? Isn't it that "dragon" is "race" or "kind" and "warrior" is a "profession" or "occupation" of "creature"? IOW these feel like properties or components of every being. The difference is that a base class is too rigid and too closely coupled to serve as property or component. We can have type of component dynamically changing but we can't have dynamically changing base subobjects. For example it is imaginable how that "dragon warrior" may want one day to change to something like "dragon gladiator" or "dragon mercenary" during life-time of it. What to do then? > inheritance case with (a) common base(s). And if you do, should there be > just a single copy of that base shared by the whole object, or does each > path to it need their own distinct copy. I understand how the diamond works and what it does. I still maintain my impression that concrete "diamond" is where relations between classes are somehow made incorrectly. It can perhaps be that it has happened in real application already made and we have just to maintain it without big corrections in the data architecture. So there the virtual inheritance is sort of fix. I would perhaps just push through the correction because it is hard for me to imagine the benefits of it. |
Juha Nieminen <nospam@thanks.invalid>: Jun 30 01:24PM >> diamond inheritance. C++ also offers another solution (which is not >> only a bit more efficient, but also feasible in some situations). > What is the solution? If you don't use virtual inheritance, then the common base class will be duplicated for each of the derived classes. In other words, the most derived class will have inside it everything from Der1 and everything from Der2 independently (which means that the things from Base will be duplicated: The Der1 part will have its own version of it and the Der2 part will have its own version.) This is not always desired. You may want the members of Base to appear in Join only once, and for the Der1 and Der2 code to refer to that one single Base data. (This requires the compiler to generate special code in the member functions of Der1 and Der2 to access the base class in a special way. This is what you are telling when you are inheriting virtually.) One example that comes to mind: You have an intrusive smart pointer, and the classes that it can handle are derived from a special class that contains a reference count. In other words, you can have something like: class MyClass1: public ReferenceCountable { ... }; class MyClass2: public ReferenceCountable { ... }; Now for one reason or another you need to multiple-inherit from those two classes: class Derived: public MyClass1, public MyClass 2 { ... }; Now how would your smart pointer be able to handle instance of this Derived class? It has 'ReferenceCountable' as its base class... but twice. Which one should it use, and how? (Obviously it ought to use only one of them, else it won't work properly.) In this case you want 'ReferenceCountable' to appear in 'Derived' only once, and thus your smart pointer will be able to unambiguously use that data. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
"Öö Tiib" <ootiib@hot.ee>: Jun 30 06:46AM -0700 On Tuesday, 30 June 2015 16:24:48 UTC+3, Juha Nieminen wrote: > In this case you want 'ReferenceCountable' to appear in 'Derived' > only once, and thus your smart pointer will be able to unambiguously > use that data. Ok, now that makes sense. It somewhat feels also a great explanation why to use 'std::make_shared' instead of intrusive refcounting. I always suggested it but did not have clear examples why. Here 'std::make_shared' seems both simpler and more efficient. Thanks. |
Martijn van Buul <pino@dohd.org>: Jun 30 03:26PM * Öö Tiib: > instead of intrusive refcounting. I always suggested it but did not have > clear examples why. Here 'std::make_shared' seems both simpler and > more efficient. Except that it isn't the same, and sometimes the differences matter, and without further knowledge of the context it's hard to say whether it is "more efficient" or not. I once rewrote a framework that used shared_ptr to intrusive_ptr, because it allowed me to avoid using new. The resulting gain in speed (and reduced memory fragmentation) was significant. Note that I'm not saying that intrusive_ptr is generally better than shared_ptr. It's not, but sometimes intrusive_ptr works where shared_ptr doesn't. The same can be said for most of the *intrusive part of Boost. -- Martijn van Buul - pino@dohd.org |
JiiPee <no@notvalid.com>: Jun 30 06:29AM +0100 "- Alf [Sorry, I inadvertently first hit "Reply" instead of "Follow up"] " Good one/spot Alf... :) Just watched a good Scott Maeyrs Video about software design. And that was just one of his point: Button names are not understandable. In thunderbird newsgroup interface you have just that problem as Alf writes: replying to a message there are Follow up and Reply button. Me also (and I bet many many others) have pressed many times that Reply button. I guess Scott would also complain about it :). I guess better would be: Reply = reply to newgroup Reply Sender = replying to sender or something else... Also buttons could be far away from each others. Just came to my mind as watched that video so recently :). But Scott opened my eyes , so this is sure what he would also say here. But otherwise Thunderbird is a good program. |
JiiPee <no@notvalid.com>: Jun 30 06:34AM +0100 On 30/06/2015 06:29, JiiPee wrote: > writes: replying to a message there are Follow up and Reply button. > Me also (and I bet many many others) have pressed many times that > Reply button. So, if me also have done that (and its rare I press wrong buttons in programs) - and others as well - that is a good indication that the design makes people easy to do it the wrong way. |
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. |