- We've won! - 17 Updates
- Longest word in a dictionary problem -- which container - 3 Updates
- Is this sorting predicate ok? - 5 Updates
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 20 12:47AM On Mon, 19 Nov 2018 14:55:51 +0100 > parameter itself (when not using references) is rarely helpful - it does > not affect the calling function at all, but makes the types harder to > read. So I would never write "void * const" as a parameter type. Const pointers (as opposed to pointers to const) are quite rare in my experience. If I want an unseatable reference, I take the view that that is what C++ references are for. |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Nov 19 09:15PM -0800 On 11/19/2018 4:47 PM, Chris Vine wrote: > Const pointers (as opposed to pointers to const) are quite rare in my > experience. If I want an unseatable reference, I take the view that > that is what C++ references are for. Agreed. Actually, this was another little habit of mine wrt my "self" pointer: it shall not be modified. Ack. ;^o |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Nov 19 10:19PM -0800 On 11/19/2018 9:15 PM, Chris M. Thomasson wrote: >>>>> On 19/11/18 10:06, Rick C. Hodgin wrote: >>>>>> In fp_write(), what's the difference between: >>>>>> void* const [...] >> that is what C++ references are for. > Agreed. Actually, this was another little habit of mine wrt my "self" > pointer: it shall not be modified. Ack. ;^o Well, here it goes again with my habit. Take a look at the self points in my code for a fractal reverse Julia 2-ary plotter the creates a text based PPM image called "ct_cipher_rifc.ppm": https://github.com/ChrisMThomasson/fractal_cipher/blob/master/RIFC/ct_bin_ppm.c ________________ // Compute the fractal void ct_ifs( struct ct_plane* const self, double complex z, double complex c, double ratio, unsigned long n ) [...] ________________ Ummm, "struct ct_plane* const self"... ;^o if you run it, there will be a new file called: "ct_cipher_rifc.ppm" on your system. So, be aware of that. Good thing this is my own personal software. Yikes! |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Nov 20 06:49AM On Tue, 2018-11-20, Chris Vine wrote: ... > Const pointers (as opposed to pointers to const) are quite rare in my > experience. If I want an unseatable reference, I take the view that > that is what C++ references are for. I may use const pointers whenever I use pointers, just like I may use const int whenever I use int. (I don't use pointers a lot, though.) /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
David Brown <david.brown@hesbynett.no>: Nov 20 09:27AM +0100 On 19/11/18 23:56, Chris M. Thomasson wrote: > Fwiw, I put the const in the interface to attempt to get the point > across that this parameter shall never be mutated by a function. Sort of > a contract, documented within the API itself. Except for reference parameters, parameters are /never/ mutated by a function. This is basic stuff - parameters in C are always pass by value. If you think putting "const" in a non-reference parameter tells the user something useful, then either /you/ misunderstand how parameters work in C and C++, or you think your users misunderstand it. For reference parameters, it is essential to distinguish between const and non-const parameters - precisely because with pass-by-reference a function /can/ mutate the calling function arguments. So please do not add unnecessary const qualifiers to non-reference parameters in a function. Put const on the pointed-to types to indicate that those are not changed by the function - but don't put const on the parameters themselves. > code are basically akin to the this parameter in C++. The value of the > this pointer shall never be changed, just like the value of the self > pointer shall never be changed. Let me re-emphasise - this is pointless, because functions cannot change parameters. What would be /vastly/ more useful is to give sensible parameter names in your function declarations. You have no "self" parameters in these functions - you have anonymous parameters whose purpose is hidden. |
Louis Krupp <lkrupp@nospam.pssw.com.invalid>: Nov 20 02:40AM -0700 On Tue, 20 Nov 2018 09:27:30 +0100, David Brown <david.brown@hesbynett.no> wrote: <snip> >parameters in a function. Put const on the pointed-to types to indicate >that those are not changed by the function - but don't put const on the >parameters themselves. I worked with someone who added "const" to non-reference input-only parameters. When I asked him why, he said it helped catch buggy code that modified those parameters even if the actual function arguments wouldn't change. For example, with g++: === int square(const int x) { x += 1; // possibly a bug return x * x; } === mnr1.cxx: In function 'int square(int)': mnr1.cxx:3:10: error: assignment of read-only parameter 'x' x += 1; // possibly a bug === In Fortran, nobody would laugh at you for doing this even if the caller's value of x wouldn't change: === integer function square(x) implicit none integer, value, intent(in) :: x x = x + 1 ! possibly a bug square = x * x return end === mnr2.f90:5:0: x = x + 1 ! possibly a bug Error: Dummy argument 'x' with INTENT(IN) in variable definition context (assignment) at (1) === although lots of people would laugh at you just for using Fortran. FWIW. Louis |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Nov 20 11:38AM > the user something useful, then either /you/ misunderstand how > parameters work in C and C++, or you think your users misunderstand > it. I don't think you should make that exception for references either. In fact, C++ forbids making a reference parameter const. You can make the /target/ const, just as you can (and often should) for pointers, but the parameter itself, no. > For reference parameters, it is essential to distinguish between const > and non-const parameters - precisely because with pass-by-reference a > function /can/ mutate the calling function arguments. I don't like that wording. References can never be const -- it makes no sense. References may be to const or non const-qualified types. I know this just words, but I think they matter when explaining things. Conceptually you can have both void f(int const &a); void f(int &const a); just as you can have both void f(int const *a); void f(int *const a); The first of those is not a const pointer no matter how many times people call it one -- it's a pointer to const. Similarly, the first reference example is not a const reference. The second one would be, were it permitted (the syntax allows it of course). <snip> -- Ben. |
David Brown <david.brown@hesbynett.no>: Nov 20 12:39PM +0100 On 20/11/18 10:40, Louis Krupp wrote: > x += 1; // possibly a bug > return x * x; > } Putting "const" on the parameters in the function definition is a different thing. If you find it helps avoid bugs in the code, fine. > === > In Fortran, nobody would laugh at you for doing this even if the > caller's value of x wouldn't change: I have not used Fortran myself, but I believe its parameters were passed by reference, not value. In C++ it makes sense to mark reference parameters as const if possible. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 20 12:23PM On 20 Nov 2018 06:49:36 GMT > > that is what C++ references are for. > I may use const pointers whenever I use pointers, just like I may use > const int whenever I use int. (I don't use pointers a lot, though.) Indeed you may. I have possibly not grasped your point, but mine was that it would be rare to write: int i; int* const p = &i; It would be more normal to write the immutable pointer in reference form: int& r = i; and the same with function parameters. "Rare" does not mean "never". You might want an immutable pointer if you receive an object by pointer which you do not own and in due course you are going to pass it to another function by pointer, and you want to ensure (or document) that in the meantime you do not reseat the pointer in your code. |
David Brown <david.brown@hesbynett.no>: Nov 20 01:41PM +0100 On 20/11/18 12:38, Ben Bacarisse wrote: > fact, C++ forbids making a reference parameter const. You can make the > /target/ const, just as you can (and often should) for pointers, but the > parameter itself, no. I thought it was clear that I meant using the const to indicate that the passed-by-reference parameter was unchanged. But on re-reading, I see I was not clear enough. If we use "int" as our basic type, rather than pointers, I mean that you should not write: void foo(int const x); or void foo(const int x); because the "const" adds nothing useful to the declaration, and may be confusing. (People may think it is a distinct overload from "void foo(int x)", for example.) But with references, it /is/ important: void foo(int const &x); or void foo(const int &x); is different from void foo(int &x); > people call it one -- it's a pointer to const. Similarly, the first > reference example is not a const reference. The second one would be, > were it permitted (the syntax allows it of course). "void f(int & const a);" is not permitted, as far as I can see - from N3797 (C++14) section 8.3.2: > are introduced through the use of a typedef-name (7.1.3, 14.1) or > decltype-specificer (7.1.6.2), in which case the cv-qualifiers are > ignored. gcc gives an error "const qualifiers cannot be applied to int&". The reference itself cannot be changed after initialisation - that is a key feature of a reference. So as you say, it makes no sense for the reference to be "const", as it is always unchangeable. I fully agree that it is important to distinguish "pointer to const" from "const pointer" - these both exist, with different usages, and the distinction is critical. However, the C++ standard itself uses the term "const reference" as well as "reference to const" for things of types such as "const int&". I can appreciate that "reference to const" is more accurate, but "const reference" is a common phrase that does not suffer from the ambiguity or confusion you get with "const pointer". Of course, you might not like the wording in the standard either :-) |
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 20 05:13AM -0800 On Monday, November 19, 2018 at 8:56:05 AM UTC-5, David Brown wrote: > parameter itself ... is rarely helpful - it does > not affect the calling function at all, but makes the types harder to > read. So I would never write "void * const" as a parameter type. If I wanted a pointer that can't be altered, pointing to something that can't be altered, what would I use? const void* const p; -- Rick C. Hodgin |
David Brown <david.brown@hesbynett.no>: Nov 20 02:24PM +0100 On 20/11/18 14:13, Rick C. Hodgin wrote: > If I wanted a pointer that can't be altered, pointing to something > that can't be altered, what would I use? > const void* const p; Yes, exactly. Just to be clear - it is a good thing to make objects "const" inside functions. You have to initialise them when you declare them, as you can't assign to them later (IMHO it is usually a good thing to postpone declaring local data until you are ready to initialise it). They help stop mistakes and make it clearer to the reader (and writer!) which objects are single valued, and which will change throughout the function. It is not a bad idea to put "const" on parameters in a function definition, if you think it helps catch errors. But it is unnecessary to put "const" on parameters in a function declaration, and can cause confusion. |
James Kuyper <jameskuyper@alumni.caltech.edu>: Nov 20 09:20AM -0500 On 11/20/18 03:27, David Brown wrote: > On 19/11/18 23:56, Chris M. Thomasson wrote: ... >> a contract, documented within the API itself. > Except for reference parameters, parameters are /never/ mutated by a > function. I think you mean "arguments", not "parameters". See the definitions of those terms in 1.3.2 and 1.3.15 of the standard. int half(int count) { return count/2; } int main(void) { int i = 10000; int j = half(i); return j==5000; } "count" is a parameter of the half function, and is modified by it. "i" is the argument for a given call to that function, and is not modified by that call. A parameter is a variable local to a function, and I declare it 'const' or not on the same basis as any other local variable: if it shouldn't be changed from it's initial value, I declare it 'const'. However, that's an implementation detail that is of no relevance to the user of the function. The function declaration that is used to call a function is allowed to lack qualifiers on parameters that have those qualifiers in the function definition, and it's conventional to take advantage of that fact. |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Nov 20 02:31PM >> /target/ const, just as you can (and often should) for pointers, but the >> parameter itself, no. > I thought it was clear No you were clear and I was not confused about what you were saying. My point was to suggest another way of saying it which I think as some advantages. > that I meant using the const to indicate that the > passed-by-reference parameter was unchanged. That's another usage that I don't like! I was taught to distinguish between an argument and a parameter (though sometimes these are called actual arguments and formal arguments). In my preferred wording "a reference to const parameter makes it clear that the argument will not be changed". <snip> > reference" is a common phrase that does not suffer from the ambiguity or > confusion you get with "const pointer". > Of course, you might not like the wording in the standard either :-) Indeed not! But it's used sparingly and the context (in the cases I looked at) helps to avoid confusion. -- Ben. |
Ralf Goertz <me@myprovider.invalid>: Nov 20 03:56PM +0100 Am Tue, 20 Nov 2018 09:20:17 -0500 > return j==5000; > } > "count" is a parameter of the half function, and is modified by it. In what way is "count" modified? It would still have the same value after the return (but of course it is destroyed) that it had when the function was called. Changing the function definition to int half(const int count) { return count/2; } compiles fine. |
David Brown <david.brown@hesbynett.no>: Nov 20 04:05PM +0100 On 20/11/18 15:31, Ben Bacarisse wrote: > No you were clear and I was not confused about what you were saying. My > point was to suggest another way of saying it which I think as some > advantages. I expected that /you/ understood what I was saying, but that you thought I could be clearer for other people. At least I could have been more accurate in my wording. > actual arguments and formal arguments). In my preferred wording "a > reference to const parameter makes it clear that the argument will not > be changed". Fair enough. The terms "argument" and "parameter" are often mixed up, but your usage here is more precise than mine. >> Of course, you might not like the wording in the standard either :-) > Indeed not! But it's used sparingly and the context (in the cases I > looked at) helps to avoid confusion. "Const reference" is used more often than "reference to const" in the standard. I'm still not convinced it makes a large difference - indeed, I am quite convinced that the person asking the question understood the answer. But I agree that careful terminology is better than loose terminology even if both are understood. |
Robert Wessel <robertwessel2@yahoo.com>: Nov 20 09:05AM -0600 On Sun, 18 Nov 2018 19:29:38 +0100, Christian Gollwitzer >The main difference between the C and the C++ version is that "qsort" is >defined in a separately compiled file, while std::sort is defined in the >header file and compiled simultaneously. If distributed in the proper format, even a separately compiled qsort() should be handle-able by link time code generation, if passed a fixed pointer to the comparison function (and the comparison function is visible as well). Unfortunately, to my knowledge, that's never been done, and even if done, LTCG often is a bit conservative about that sort of thing, especially with routines that can be a bit larger, like qsort(). |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Nov 20 12:50AM > a collection of letters. For more (but perhaps still not total) clarity, > please see my code below. It's an interview question and interviewers > don't usually give total clarity either. My interpretation (and solution) is shown below, after some space in case some reader does not want to see other solutions just yet. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #include <cstring> #include <map> #include <iostream> bool characters_match(const std::map<char, int> &counts, const std::string &word) { std::map<char, int> wd_counts; for (auto c : word) if (counts.find(c) == counts.end() || counts.at(c) == wd_counts[c]) return false; else wd_counts[c] += 1; return true; } int main(int argc, char *argv[]) { if (argc == 2) { size_t max_len = std::strlen(argv[1]); std::map<char, int> counts; for (size_t i = 0; i < max_len; i++) counts[argv[1][i]] += 1; size_t cur_max_len = 0; std::string word, best_word = ""; while (std::cin >> word) if (word.length() > cur_max_len && word.length() <= max_len && characters_match(counts, word)) { cur_max_len = word.length(); best_word = word; } std::cout << "Best: " << best_word << "\n"; } else std::cerr << "one string argument please.\n"; } -- Ben. |
Louis Krupp <lkrupp@nospam.pssw.com.invalid>: Nov 20 01:14AM -0700 On Mon, 19 Nov 2018 13:16:39 -0000 (UTC), Juha Nieminen >as a preprocessing step). I think you can figure out how to make this >comparison so that what's being checked is "can this word be formed >by using letters from this group of letters?") Once the letters in the pattern are sorted, you've got the makings of a regular expression; for example, "acecad" would become "^a{0,2}c{0,2}d?e?$" . You could sort the letters in the words as Juha suggested and then offload the pattern matching to the Standard Library. >This might not be the absolutely fastest way of doing it that's >possible, but in most cases it's efficient enough. You might be able to speed it up a little by ignoring words that are shorter than the longest word that matches the pattern. If nothing else, sorting the letters and building the pattern makes it really obvious what the code is doing. How often does an interviewer see a candidate do that? Louis |
Juha Nieminen <nospam@thanks.invalid>: Nov 20 02:55PM > "^a{0,2}c{0,2}d?e?$" . You could sort the letters in the words as Juha > suggested and then offload the pattern matching to the Standard > Library. No need to do it that complicated. Since the original word has all of its letters sorted, and the given letters are also sorted, all you have to do is traverse both one letter at a time, advancing in the given letters only when the word letter doesn't match. (If a given letter becomes larger than the word letter in this manner, you can stop because you know that the word has a letter that's not among the input letters). In other words, take the first letter of the word, and advance in the given letters until you find it (or if a given letter becomes larger than the word letter, you can stop because it won't be found. Likewise if you reach the end of the given letters, of course.) Then advance in the word letters until you encounter a different letter. Rinse and repeat until you have gone through the entire word. The above is a bit lacking as a full algorithm explanation, but I'm sure it ought to be enough to give an idea. |
Paul <pepstein5@gmail.com>: Nov 19 04:08PM -0800 On Monday, November 19, 2018 at 11:01:10 PM UTC, Jorgen Grahn wrote: > I'd try to solve the problem in a way which doesn't need an unusual > predicate. Where "unusual" means roughly anything but > std::lexicographical_compare(f(a), f(b)), or whatever the syntax is. Good advice. You say "I tried to understand it, but failed." I'll explain what I was trying to do. We have a std::string, for example std::string s = "ababcoddefg"; We have a std::unordered_set<std::string> stringSet; The task is to find a longest word in stringSet that uses only letters from string s and respects the character counts. For example s has only 2 a's. So the word "aaa" would not be allowed but the word "a" would be allowed (assuming that "a" is a member of stringSet). So that raises the question of which words to try first in stringSet. Well a word can't possibly work if it's longer than s.size() so I want all words longer than s.size() to be at the bottom. Regarding words that are not longer than s.size(), I want them to be in descending order of size. That way, once you've found a word that works, you can just return it. I was trying to achieve the above by a sorting predicate. I'm not saying I was right, and that my method was good. But now I hope you understand what I was trying to do. I suppose I could experiment by creating a large set of words and examine whether the sorting has the above property. Paul |
Paul <pepstein5@gmail.com>: Nov 19 04:13PM -0800 On Monday, November 19, 2018 at 11:01:10 PM UTC, Jorgen Grahn wrote: > Side note: my compiler gives me a warning about the precedence > between || and &&. I happily admit I had to look it up; I've never > needed to memorize that particular precedence rule. ... But it doesn't need memorization or looking it up. The precedence between || and && can't be different from the precedence between + and *. Surely everyone knows that true || false && false means true || (false && false) which == true. Paul |
Paavo Helde <myfirstname@osa.pri.ee>: Nov 20 08:30AM +0200 On 19.11.2018 16:47, Paul wrote: > const int length = arrayOfLetters.size(); > auto cmp = [length](const std::string& word1, const std::string& word2)->bool{return word1.size() <= length && word2.size() > length || word1.size() > word2.size();}; > std::sort(sortedDictionary.begin(), sortedDictionary.end(), cmp); Assume length = 3 Consider x = "ab"; y = "abcd"; cmp(x, y) -> true cmp(y, x) -> true That's not going to fly. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Nov 20 06:59AM On Tue, 2018-11-20, Paul wrote: > On Monday, November 19, 2018 at 11:01:10 PM UTC, Jorgen Grahn wrote: >> On Mon, 2018-11-19, Paul wrote: ... > ... > But it doesn't need memorization or looking it up. The precedence between > || and && can't be different from the precedence between + and *. I don't immediately see a similarity between those pairs. > Surely everyone knows that true || false && false means true || (false && false) which == true. 1. Not everyone; see above. I honestly don't know, and I've been programming in C for almost thirty years. (I could learn the rule, but I have never needed to.) 2. I don't seem to be extreme; I don't use more parentheses than many others. (Although I prefer to introduce temporaries for complex expressions.) 3. Enough people seem to feel that way, or gcc wouldn't warn. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Nov 20 01:34PM >> But it doesn't need memorization or looking it up. The precedence between >> || and && can't be different from the precedence between + and *. > I don't immediately see a similarity between those pairs. If you tabulate result of +, *, || and && with bool operands you get this: + | false | true || | false | true --------+-------+------ --------+-------+------ false | false | true false | false | true true | true | true true | true | true * | false | true && | false | true --------+-------+------ --------+-------+------ false | false | false false | false | false true | false | true true | false | true You'd get the same with | and &. The same goes for set union and intersection. In a language with those operators, I'd expect union to have a lower precedence than intersection. If C++'s std::set were to add them, it would be reasonable (at least to me!) to use operator+ and operator* for them. Slightly related: if, instead of | you take ^ (exclusive or), then ^ and & are the additive and multiplicative operators of a finite field over {true, false}. That field is isomorphic to the one you get using addition and multiplication modulo 2 over {0, 1}. -- Ben. |
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