13 ms·
Obscure C++ Features
- taspeotis 13y agoThis one [1] surprised me. Q1: Is the following code legal C++? string f() { return "abc"; } void g() { const string& s = f(); cout << s << endl; // can we still use the "temporary" object? } [1] http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the...
- mhogomchungu 13y agoI do not think they had this kind of usage in mind when they allowed it and i think the use case for it is in using a const reference to a function argument.Most people use this all the time without thinking about it or wondering what is the origin of the variable they are accessing through the const reference. eg is when you have a function like below: void foo( const string& str ) { cout << str ; } The above function takes a const reference to string and uses it without caring if the passed in variable is a temporary variable or not. Now declare a function as: string bar() { return "abc" ; } and the above two function can be used with: foo( bar() ) ; I think this use case is the one that allowed the use of temporary variable from a const reference and people do this all the time.
- MaulingMonkey 13y ago> I do not think they had this kind of usage in mind when they allowed it I think they did based on 8.5.3 which has this example: struct A { }; struct B : public A { } b; extern B f(); const A& rca = f(); // Either bound to the A sub-object of the B rvalue, // or the entire B object is copied and the reference // is bound to the A sub-object of the copy As well as 12.2 para 5: class C { // ... public: C(); C(int); friend C operator+(const C&, const C&); ˜C(); }; C obj1; const C& cr = C(16)+C(23); C obj2; In the C++ standard which talks about the temporary bound to cr existing for the duration of the entire program? Moreover, why would a rule for const references be specifically needed to handle foo( bar() );, but no equivalent rule for bar().foo(); which handles an implicit non-const pointer?
- Jare 13y agoI believe it was explicitly defined to support this use case, since the extra lifetime it is added on top of the regular "temporary lasts until the end of the full expression in which it is created". The "full expression" clause would be sufficient for function parameters, because the expression is not finished until the entire expression has been evaluated, and this includes executing and returning from the function that received the temporary. In an indirect way though I agree: it is important for the language to make it easy to break apart complex expressions, but without this lifetime extension, I suspect it may not be possible to un-nest function calls without creating more copies (RVO may prove me wrong though - not studied the case in full).
- mtdewcmu 13y agoOf course, this is perfectly good C: const char *f() { return "abc"; } void g() { const char * s = f(); puts(s); } Nothing temporary is created at all. It's rather convenient.
- kalimatas 13y agoI knew about the first sentence, but the second really obscure. Accessing an element of an array via ptr[3] is actually just short for *(ptr + 3). This can be equivalently written as *(3 + ptr) and therefore as 3[ptr], which turns out to be completely valid code.
- Skinney 13y agoThis was actually written in the book I used to learn C (I think, at least I knew this early on). It seems completely irrational when someone tells you that ptr[3] == 3[ptr], but with the above explination it makes perfect sence.
- chmike 13y agoYes and it also explains why array indexing starts at 0.
- unfamiliar 13y agoNot really. It would be just as easy to say a[x]=*(a+x-1) and let array indices start at 1.
- valisystem 13y agoactually yes, [] derives from BCPL, see evincarofautumn comment just above. ( link to comment, https://news.ycombinator.com/item?id=6886488 https://news.ycombinator.com/item?id=6886488 derived from this submission : https://news.ycombinator.com/item?id=6879478 https://news.ycombinator.com/item?id=6879478 )
- evincarofautumn 13y agoThe BCPL infix “!” operator makes it a bit clearer, I think: BCPL C !a *a a ! 0 a[0] 0 ! a 0[a] !(a + 0) *(a + 0) !(0 + a) *(0 + a) That’s where C got its 0-based semantics from—it would be a nasty surprise if 0 weren’t the identity for pointer addition!
- eonil 13y agoI couldn't even imagine something like ref-qualifier and function as template parameter.
- kenrose 13y agoThe function try blocks is new to me. It's actually kind of elegant (for C++). Granted, the reason I've probably never encountered it in the wild is that there are probably very few scenarios where you have a member in the initializer list where you want to handle an exception on initialization. If you were trying to handle an exception of an instance variable initializing, most people would just move that member to the constructor body (e.g., if you have a pointer). The only time this would be useful then is for members that don't have default initializers (e.g., a reference).
- evincarofautumn 13y agoIt also just removes a level of nesting, which is nice by itself.
- b-johansson 13y agoFunction try blocks are also extra tricky because at the end of the catch block the exception is automatically rethrown. http://www.drdobbs.com/sutters-mill-constructor-failures-or-the/184401316 http://www.drdobbs.com/sutters-mill-constructor-failures-or-... has a lot of details on function try blocks.
- jasonzemos 13y agoIt's nice to avoid the default initialization and construct a member directly with the argument you want. Then you can construct a second member which might depend on that previous one, etc. This can even include lambdas right in the initialization list, and all of this may throw and log an error with the catch block. Personally, I rarely like to see code in the actual constructor body anymore.
- wyager 13y agoEvery time I read about obscure C++ features, the more I'm convinced that the language needs to be torn down and rebuilt from scratch.
- k00pa 13y agoSo every language should be dump down version of Python or something?
- TazeTSchnitzel 13y agoHave a look at D: It's what C++ should be.
- nikbackm 13y agoAlready been done a few times. (See D and Rust) But the result will no longer be C++ for better and worse.
- richo 13y agoC++11 is actually really, /really/ nice. If you haven't already you should read up on it. I was hating c++ for vague reasons I couldn't place. I was wrong.
- 72deluxe 13y agoI would agree. Although my work involves writing some code under VS2010 on Windows so I can't use C++11 features, I still read Stroustrup's book. The tour of C++ is particularly helpful as it covers many of the new features, and offers tips like making the compiler work for you. Stroustrup wrote an interesting paper (wish I could find it) in IEEE/Computer magazine that strongly advocated static code and not overuse of dynamic_casts etc. for speedy programs - this is making the compiler do all of the optimization instead of doing everything/making many decisions at run time. The Wikipedia article on C++11 covers many of the new features quite well, but Stroustrup's recent revision of the C++ book is a joy to read - the fonts help, as the previous one had some pretty horrible fonts in my opinion.
- koyote 13y agoVS2010 actually does implement quite a few of C++11's features, you have to be careful though and better read the MSDN documentation for each of them. A weird case I found recently was that the VS2010 implementation of std::to_string(...) only supports long long, unsigned long long and long double. http://msdn.microsoft.com/en-us/library/ee404875(v=vs.100).aspx http://msdn.microsoft.com/en-us/library/ee404875(v=vs.100).a... Not very useful for most cases. Luckily VS2012+ supports the rest of the number types.
- fhd2 13y agoC++98 with TR1 comes close enough, it's what I use for lack of C++11 compiler support. The funny thing is that "C++ as most people know it" is pretty far from "C++ as it was intended". Luckily, C++11 is nudging everyone towards the latter.
- ret 13y agoSee also FQA: http://www.yosefk.com/c++fqa/index.html http://www.yosefk.com/c++fqa/index.html
- voyou 13y agoAre these really that obscure? Well, the 3[array] thing is unexpected and also not something you would use in real code, so it reasonably counts as obscure (although it's such a hoary example of "obscure C" that it's almost familiar). But pointers-to-members, template-template parameters, and the overloads of ++ and -- are, I would have thought, just standard features you would learn in the normal course of learning the language.
- EpicEng 13y agoI thought that the reference qualifiers on member functions and perhaps the function try/catch blocks were fairly obscure, but yeah, not really anything else.
- 10098 13y agoYeah, out of all these only the "most vexing parse" struck me as somewhat obscure simply because it's so insidious. The rest... not really that obscure. I mean, come on. a[3] equivalent of *(a+3)? That's just pointer arithmetic. Most of the other stuff is probably intermediate level.
- Jare 13y agoMost people understand that a[3] and *(a + 3) yield the same result, not that they are actually identical in terms of language syntax.
- jheriko 13y agothey really aren't identical in the general case - this is a mistake on the part of the author. trivially consider the case where i overload operator[]...
- CJefferson 13y agoYes, this is more of an obscure C feature (they are exactly the same in all cases in C, the standard defines a[b] as *(a+b)), which is inherited by C++.
- 72deluxe 13y agoMost people have come across member function pointers - event handling! They are (in some libraries) wrapped in macros for easier readability but most beginners use function pointers without realising.
- deleted 13y ago[deleted]
- jheriko 13y agosurprised that most of this is considered obscure... and also teh square bracket thing is only for built-in types (e.g. pointer types) because it can be overloaded... the constructor vs. function choice is a classic gotcha for instance. i've had to explain it to juniors many times.
- throwaway0094 13y ago"The tokens and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq, <%, %>, <:, and :> can be used instead of the symbols &&, &=, &, |, ~, !, !=, ||, |=, ^, ^=, {, }, [, and ]." In C, the first few are only if you include the C99 header <iso646.h> (the later ones are just digraphs). Are they included by default in C++?
- agoandanon 13y agoThis article misses WHY certain things are the case, and has several incomplete or incorrectly-explained points.
- BruceIV 13y agoYeah, the one that got me is "branch on variable declaration", which I believe is actually a special case of the fact that assignment is actually an expression which returns the assigned value; `a = b = c = 42;` works for the same reason.
- mcguire 13y ago"The tokens and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq..." Hey, I remember when those were introduced! I was the sysadmin responsible for supporting the default gcc on all of a computer science department's non-research machines and upgraded gcc between semesters. I then got to spend a couple of days rewriting some grad students' code because the had used "and" and "or" as variable names.[1] Fun times! [1] Many of whom were upset because the upgrade had changed the preprocessor/compiler interface and broke their research compiler.
- andhow 13y agoI've always thought that this ranked among the most obscure: typedef int F(int); class C { F f; }; int C::f(int i) { return i; } I've never seen it used in practice...