114

No C++ love when it comes to the "hidden features of" line of questions? Figured I would throw it out there. What are some of the hidden features of C++?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Craig H
  • 7,949
  • 16
  • 49
  • 61
  • @Devtron - I've seen some awesome bugs (i.e. unexpected behavior) sold as features. In fact, the games industry actually tries to make this happen nowadays and calls it "emergent gameplay" (also, check out "TK Surfing" from Psi-Ops, was purely a bug, then they left it as is and its one of the best features of the game IMHO) – Grant Peters Jan 06 '10 at 15:11
  • 5
    @Laith J: Not very many people have read the 786-page ISO C++ standard from cover to cover -- but I suppose you have, and you've retained all of it, right? – j_random_hacker Feb 14 '10 at 19:20
  • 2
    @Laith, @j_random: See my question "What is a programmer's joke, how do I recognize it, and what is the appropriate response" at http://stackoverflow.com/questions/1/you-have-been-link-rolled. –  Feb 26 '10 at 08:57
  • See http://meta.stackexchange.com/questions/56669/should-hidden-features-of-x-be-removed-closed-locked, http://meta.stackexchange.com/questions/57226/should-we-have-a-list-of-x-close-reason and related Meta posts. –  Jul 16 '10 at 02:14

64 Answers64

308

Most C++ programmers are familiar with the ternary operator:

x = (y < 0) ? 10 : 20;

However, they don't realize that it can be used as an lvalue:

(a == 0 ? a : b) = 1;

which is shorthand for

if (a == 0)
    a = 1;
else
    b = 1;

Use with caution :-)

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
238

You can put URIs into C++ source without error. For example:

void foo() {
    http://stackoverflow.com/
    int bar = 4;

    ...
}
Ben
  • 339
  • 1
  • 2
  • 5
  • 41
    But only one per function, i suspect? :) – Constantin Oct 05 '08 at 17:40
  • Is this a bug? What's it meant to do? I tried it and it indeed compiled without error; I did get a warning: warning C4102: 'http' : unreferenced label – jpoh Oct 21 '08 at 05:56
  • 3
    Just don't try adding more than one per source file :P – X-Istence Oct 26 '08 at 15:21
  • 51
    @jpoh: http followed by a colon becomes a "label" which you use in a goto statement later. you get that warning from your compiler because it's not used in any goto statement in the above example. – utku_karatas Nov 04 '08 at 17:07
  • 9
    You can add more than one as long as they have different protocols! ftp://ftp.microsoft.com gopher://aerv.nl/1 and so on... – Daniel Earwicker Mar 27 '09 at 21:28
  • 4
    @Pavel: An identifier followed by a colon is a label (for use with `goto`, which C++ does have). Anything following two slashes is a comment. Therefore, with `http://stackoverflow.com`, `http` is a label (you could theoretically write `goto http;`), and `//stackoverflow.com` is just an end-of-line comment. Both of these are legal C++, so the construct compiles. It doesn't do anything vaguely useful, of course. – David Thornley May 28 '10 at 21:55
  • If you have Warnings as Errors switched on it won't build, in VS2005 at least – Chris Huang-Leaver Jan 07 '11 at 12:21
  • @Chris: you can fix that by adding a `goto http;` ;-) – Tony Delroy Jan 24 '11 at 10:15
  • 8
    Unfortunately `goto http;` doesn't actually follows the URL. :( – Yakov Galka Aug 02 '11 at 17:01
  • @titaniumdecoy Wait, Java supports `goto`s? – Mateen Ulhaq Sep 27 '11 at 00:17
  • @muntoo, actually yes, sort of. http://stackoverflow.com/a/2545160/65977 – Tyler Dec 14 '11 at 04:18
140

Pointer arithmetics.

C++ programmers prefer to avoid pointers because of the bugs that can be introduced.

The coolest C++ I've ever seen though? Analog literals.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
119

I agree with most posts there: C++ is a multi-paradigm language, so the "hidden" features you'll find (other than "undefined behaviours" that you should avoid at all cost) are clever uses of facilities.

Most of those facilities are not build-in features of the language, but library-based ones.

The most important is the RAII, often ignored for years by C++ developers coming from the C world. Operator overloading is often a misunderstood feature that enable both array-like behaviour (subscript operator), pointer like operations (smart pointers) and build-in-like operations (multiplying matrices.

The use of exception is often difficult, but with some work, can produce really robust code through exception safety specifications (including code that won't fail, or that will have a commit-like features that is that will succeed, or revert back to its original state).

The most famous of "hidden" feature of C++ is template metaprogramming, as it enables you to have your program partially (or totally) executed at compile-time instead of runtime. This is difficult, though, and you must have a solid grasp on templates before trying it.

Other make uses of the multiple paradigm to produce "ways of programming" outside of C++'s ancestor, that is, C.

By using functors, you can simulate functions, with the additional type-safety and being stateful. Using the command pattern, you can delay code execution. Most other design patterns can be easily and efficiently implemented in C++ to produce alternative coding styles not supposed to be inside the list of "official C++ paradigms".

By using templates, you can produce code that will work on most types, including not the one you thought at first. You can increase type safety,too (like an automated typesafe malloc/realloc/free). C++ object features are really powerful (and thus, dangerous if used carelessly), but even the dynamic polymorphism have its static version in C++: the CRTP.

I have found that most "Effective C++"-type books from Scott Meyers or "Exceptional C++"-type books from Herb Sutter to be both easy to read, and quite treasures of info on known and less known features of C++.

Among my preferred is one that should make the hair of any Java programmer rise from horror: In C++, the most object-oriented way to add a feature to an object is through a non-member non-friend function, instead of a member-function (i.e. class method), because:

  • In C++, a class' interface is both its member-functions and the non-member functions in the same namespace

  • non-friend non-member functions have no privileged access to the class internal. As such, using a member function over a non-member non-friend one will weaken the class' encapsulation.

This never fails to surprise even experienced developers.

(Source: Among others, Herb Sutter's online Guru of the Week #84: http://www.gotw.ca/gotw/084.htm )

paercebal
  • 81,378
  • 38
  • 130
  • 159
  • +1 very thorough answer. it's incomplete for obvious reasons (otherwise there wouldn't be "hidden features" anymore!) :p in the first point at the end of the answer, you mentioned members of a class interface. do you mean ".. is both its member-functions and the *friend* non-member functions"? – wilhelmtell Oct 03 '08 at 22:31
  • CRTP - http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern – J.J. Oct 13 '08 at 15:44
  • what you are mentioning about with 1 must be koenig lookup, right? – Özgür Oct 30 '08 at 00:43
  • 1
    @wilhelmtell: No no no... :-p ... I DO mean "its member-functions and NON-FRIEND non-member functions".... Koenig's Lookup will make sure these functions will be considered sooner than other "outside" functions in its search for symbols – paercebal Oct 30 '08 at 21:45
  • @Comptrol: You're almost right, it is the *consequence* of Keonig's Lookup. – paercebal Oct 30 '08 at 21:45
  • 7
    Great post, and +1 especially for the last part, which far too few people realize. I'd probably add the Boost library as a "hidden feature" as well. I pretty much consider it the standard library that C++ should have had. ;) – jalf Nov 19 '08 at 17:04
118

One language feature that I consider to be somewhat hidden, because I had never heard about it throughout my entire time in school, is the namespace alias. It wasn't brought to my attention until I ran into examples of it in the boost documentation. Of course, now that I know about it you can find it in any standard C++ reference.

namespace fs = boost::filesystem;

fs::path myPath( strPath, fs::native );
Jason Mock
  • 823
  • 1
  • 10
  • 19
  • 1
    I guess this is useful if you don't want to use `using`. – Siqi Lin Aug 20 '10 at 02:44
  • 4
    It's also useful as a way to switch between implementations, whether selecting say thread-safe versus non-thread-safe, or version 1 versus 2. – Tony Delroy Jan 24 '11 at 10:22
  • 3
    It's especially useful if you're working on a very large project with large namespace hierarchies and you don't want your headers to cause namespace pollution (and you want your variable declarations to be human-readable). – Brandon Bohrer Mar 17 '11 at 00:40
102

Not only can variables be declared in the init part of a for loop, but also classes and functions.

for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) {
    ...
}

That allows for multiple variables of differing types.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 31
    Nice to know that you can do it, but personally I'd really try to avoid doing anything like that. Mostly because it's difficult to read. – Zoomulator Jul 10 '09 at 21:24
  • @Sir: It might be interesting to use for generated code or macro trickery, though. – sbi May 05 '10 at 14:07
  • -1: Sorry, but unfortanutelly it doesn't work on VS2008. for(struct { int a; float b; } loop = { 1, 2 };;); causes: "error C2332: 'struct' : missing tag name" – Valentin H Nov 24 '10 at 17:33
  • 2
    Actually, what would work in this context is using a pair: for ( std::pair loop=std::make_pair(1,2); loop.first > 0; loop.second+=1) – Valentin H Nov 24 '10 at 17:44
  • 2
    @Valentin well then I recommend you to try and make a bugreport against VS2008 instead of downvoting the hidden feature. It's clearly the fault of your compiler. – Johannes Schaub - litb Nov 24 '10 at 21:21
  • 2
    Hmm, it doesn't work in msvc10 either. How sad :( – avakar Nov 24 '10 at 22:25
  • 2
    @avakar in fact, gcc introduced a bug that makes it reject too, in v4.6 :) see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46791 – Johannes Schaub - litb Dec 29 '10 at 22:35
  • Reminds me of 'write a C program to output your name but no using semicolons in your program'. We just use **if (printf("Nav"))** – Nav Feb 05 '11 at 08:54
77

The array operator is associative.

A[8] is a synonym for *(A + 8). Since addition is associative, that can be rewritten as *(8 + A), which is a synonym for..... 8[A]

You didn't say useful... :-)

Colin Jensen
  • 3,739
  • 1
  • 20
  • 17
73

One thing that's little known is that unions can be templates too:

template<typename From, typename To>
union union_cast {
    From from;
    To   to;

    union_cast(From from)
        :from(from) { }

    To getTo() const { return to; }
};

And they can have constructors and member functions too. Just nothing that has to do with inheritance (including virtual functions).

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Interesting! So, must you initialise all members? Does it follow the usual struct order, implying that the last member will be initialised "on top of" earlier members? – j_random_hacker Jan 22 '09 at 09:31
  • j_random_hacker oh, right that's nonsense. good catch. i wrote it as it would be a struct. wait i'll fix it – Johannes Schaub - litb Jan 22 '09 at 11:22
  • Doesn't this invoke undefined behavior? – Greg Bacon Jan 30 '10 at 14:11
  • 7
    @gbacon, yes it does invoke undefined behavior if `From` and `To` are set and used accordingly. Such an union can be used with defined behavior though (with `To` being an array of unsigned char or a struct sharing an initial sequence with `From`). Even if you use it in an undefined way, it might still be useful for low-level work. Anyway, this is just one example of an union template - there may be other uses for an templated union. – Johannes Schaub - litb Jan 30 '10 at 15:32
  • That is interesting, never knew that unions actually had those features from classes and structs! – Ramon Zarazua B. Feb 26 '10 at 08:58
  • 3
    Careful with the constructor. Note that you are required to only construct the first element, and it's only allowed in C++0x. As of the current standard, you have to stick to trivially constructible types. And no destructors. – Potatoswatter Feb 26 '10 at 09:18
  • So basically you're doing this? `*(B *)&a` – Nick Bedford Mar 26 '10 at 00:39
  • @JohannesSchaub-litb: also, bitfields can be templated: http://stackoverflow.com/a/8309592/85371 – sehe Dec 04 '11 at 01:06
72

C++ is a standard, there shouldn't be any hidden features...

C++ is a multi-paradigm language, you can bet your last money on there being hidden features. One example out of many: template metaprogramming. Nobody in the standards committee intended there to be a Turing-complete sublanguage that gets executed at compile-time.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
65

Another hidden feature that doesn't work in C is the functionality of the unary + operator. You can use it to promote and decay all sorts of things

Converting an Enumeration to an integer

+AnEnumeratorValue

And your enumerator value that previously had its enumeration type now has the perfect integer type that can fit its value. Manually, you would hardly know that type! This is needed for example when you want to implement an overloaded operator for your enumeration.

Get the value out of a variable

You have to use a class that uses an in-class static initializer without an out of class definition, but sometimes it fails to link? The operator may help to create a temporary without making assumptins or dependencies on its type

struct Foo {
  static int const value = 42;
};

// This does something interesting...
template<typename T>
void f(T const&);

int main() {
  // fails to link - tries to get the address of "Foo::value"!
  f(Foo::value);

  // works - pass a temporary value
  f(+Foo::value);
}

Decay an array to a pointer

Do you want to pass two pointers to a function, but it just won't work? The operator may help

// This does something interesting...
template<typename T>
void f(T const& a, T const& b);

int main() {
  int a[2];
  int b[3];
  f(a, b); // won't work! different values for "T"!
  f(+a, +b); // works! T is "int*" both time
}
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
61

Lifetime of temporaries bound to const references is one that few people know about. Or at least it's my favorite piece of C++ knowledge that most people don't know about.

const MyClass& x = MyClass(); // temporary exists as long as x is in scope
chollida
  • 7,834
  • 11
  • 55
  • 85
MSN
  • 53,214
  • 7
  • 75
  • 105
52

A nice feature that isn't used often is the function-wide try-catch block:

int Function()
try
{
   // do something here
   return 42;
}
catch(...)
{
   return -1;
}

Main usage would be to translate exception to other exception class and rethrow, or to translate between exceptions and return-based error code handling.

vividos
  • 6,468
  • 9
  • 43
  • 53
  • I don't think you can `return` from catch block of Function Try, only rethrow. – Constantin Oct 05 '08 at 17:45
  • I just tried compiling the above, and it gave no warning. I think the above example works. – vividos Oct 22 '08 at 07:45
  • 7
    return is only banned for constructors. A constructor's function try block will catch errors initializing the base and members (the only case where a function try block does something different than just having a try inside the function); not re-throwing would result in an incomplete object. – puetzk Dec 18 '08 at 04:42
  • Yes. This is very useful. I wrote macros BEGIN_COM_METHOD and END_COM_METHOD to catch exceptions and return HRESULTS so that exceptions didn't leak out of a class implementing a COM interface. It worked well. – Scott Langham Feb 18 '09 at 12:47
  • @puetzk I guess It could become very usefull to return a "DefaultObject" from a constructor that failed. Like if the constructor fail. You can still return an empty object. Like you want to load a image. On loading error it return a default image. – Loïc Faure-Lacroix Mar 17 '09 at 01:19
  • This is pretty rad. I had no idea you could that, and it doesn't appear to people that it would even compile. – Nick Bedford Mar 26 '10 at 00:43
  • 3
    As pointed out by @puetzk, this is the only way to handle exceptions thrown by *anything* in a constructor's **initialiser list**, such as base classes' constructors or those of data members. – anton.burger Jun 23 '10 at 10:56
  • @kizzx: it saves you one open and one close brace. – Yakov Galka Dec 31 '10 at 16:48
  • @kizzx: it also saves further indentation of the function body... nice if you're lazy to reindent or work in a fixed-width screen and want to use more of it. – Tony Delroy Jan 24 '11 at 10:27
44

Many know of the identity / id metafunction, but there is a nice usecase for it for non-template cases: Ease writing declarations:

// void (*f)(); // same
id<void()>::type *f;

// void (*f(void(*p)()))(int); // same
id<void(int)>::type *f(id<void()>::type *p);

// int (*p)[2] = new int[10][2]; // same
id<int[2]>::type *p = new int[10][2];

// void (C::*p)(int) = 0; // same
id<void(int)>::type C::*p = 0;

It helps decrypting C++ declarations greatly!

// boost::identity is pretty much the same
template<typename T> 
struct id { typedef T type; };
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Interesting, but initially I actually had _more_ trouble reading some of those definitions. Another way to fix the inside-out problem with C++ declarations is to write some template type aliases: `template using function = Ret (Args...); template using pointer = *T;` -> `pointer> f(pointer>);` or `pointer f(pointer);` or `function>,pointer>> f;` – bames53 Jan 09 '12 at 15:27
42

A quite hidden feature is that you can define variables within an if condition, and its scope will span only over the if, and its else blocks:

if(int * p = getPointer()) {
    // do something
}

Some macros use that, for example to provide some "locked" scope like this:

struct MutexLocker { 
    MutexLocker(Mutex&);
    ~MutexLocker(); 
    operator bool() const { return false; } 
private:
    Mutex &m;
};

#define locked(mutex) if(MutexLocker const& lock = MutexLocker(mutex)) {} else 

void someCriticalPath() {
    locked(myLocker) { /* ... */ }
}

Also BOOST_FOREACH uses it under the hood. To complete this, it's not only possible in an if, but also in a switch:

switch(int value = getIt()) {
    // ...
}

and in a while loop:

while(SomeThing t = getSomeThing()) {
    // ...
}

(and also in a for condition). But i'm not too sure whether these are all that useful :)

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Neat! I never knew you could do that... it would have (and will) save some hassle when writing code with error return values. Is there any way to still have a conditional instead of just != 0 in this form? if((int r = func()) < 0) doesn't seem to work... – puetzk Dec 18 '08 at 04:58
  • puetzk, no there isn't . but glad you like it :) – Johannes Schaub - litb Jan 11 '09 at 03:58
  • Actually a friend of mine had to use this first feature to precisely craft a very tricky macro that was needed in the existing system. – Kamil Szot Sep 09 '09 at 22:37
  • +1 Enjoy this link: http://www.ddj.com/cpp/184401728 – Fernando N. Nov 05 '09 at 23:25
  • This is really only hidden for people who never seriously wrote C code. It's *very* common to capture return values in variables like this. – Frerich Raabe Nov 20 '09 at 16:51
  • 4
    @Frerich, this is not possible in C code at all. I think you are thinking of `if((a = f()) == b) ...`, but this answer actually declares a variable in the condition. – Johannes Schaub - litb Nov 20 '09 at 17:17
  • This isn't very different from `for (int i=foo(); i – AngryWhenHungry Jun 18 '10 at 09:07
  • 1
    @Angry it's very different, because the variable declaration is tested for its boolean value straight away. There is a mapping to for-loops too, which looks like `for(...; int i = foo(); ) ...;` This will go through the body as long as `i` is true, initializing it each time again. The loop that you show is simply demonstrating a variable declaration, but not a variable declaration that simultanuously acts as a condition :) – Johannes Schaub - litb Jun 18 '10 at 10:24
  • 5
    Very good, except you didn't mention the intended use for this feature was for dynamic pointer casts, I believe. – mmocny Mar 05 '11 at 16:03
29

Preventing comma operator from calling operator overloads

Sometimes you make valid use of the comma operator, but you want to ensure that no user defined comma operator gets into the way, because for instance you rely on sequence points between the left and right side or want to make sure nothing interferes with the desired action. This is where void() comes into game:

for(T i, j; can_continue(i, j); ++i, void(), ++j)
  do_code(i, j);

Ignore the place holders i put for the condition and code. What's important is the void(), which makes the compiler force to use the builtin comma operator. This can be useful when implementing traits classes, sometimes, too.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • I just used this to finish off my [overkill expression ignorer](http://stackoverflow.com/questions/4030959/will-a-variablename-c-statement-be-a-no-op-at-all-times/4030983#4030983). :) – GManNickG Feb 04 '11 at 02:17
28

Array initialization in constructor. For example in a class if we have a array of int as:

class clName
{
  clName();
  int a[10];
};

We can initialize all elements in the array to its default (here all elements of array to zero) in the constructor as:

clName::clName() : a()
{
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Sirish
  • 9,183
  • 22
  • 72
  • 107
27

Oooh, I can come up with a list of pet hates instead:

  • Destructors need to be virtual if you intend use polymorphically
  • Sometimes members are initialized by default, sometimes they aren't
  • Local clases can't be used as template parameters (makes them less useful)
  • exception specifiers: look useful, but aren't
  • function overloads hide base class functions with different signatures.
  • no useful standardisation on internationalisation (portable standard wide charset, anyone? We'll have to wait until C++0x)

On the plus side

  • hidden feature: function try blocks. Unfortunately I haven't found a use for it. Yes I know why they added it, but you have to rethrow in a constructor which makes it pointless.
  • It's worth looking carefully at the STL guarantees about iterator validity after container modification, which can let you make some slightly nicer loops.
  • Boost - it's hardly a secret but it's worth using.
  • Return value optimisation (not obvious, but it's specifically allowed by the standard)
  • Functors aka function objects aka operator(). This is used extensively by the STL. not really a secret, but is a nifty side effect of operator overloading and templates.
Robert
  • 131
  • 2
  • 4
  • 16
    pet hate: no defined ABI for C++ apps, unlike C ones that everyone uses because every language can guarantee to call a C function, no-one can do the same for C++. – gbjbaanb Sep 25 '08 at 08:52
  • 8
    Destructors need to be virtual only if you intend to destroy polymorphically, which is a little subtly different from the first point. – David Rodríguez - dribeas Jan 03 '09 at 13:25
  • 2
    With C++0x local types can be used as template parameters. – tstenner Apr 23 '09 at 13:21
  • 1
    With C++0x, destructors will be virtual if the object has any virtual functions (i.e. a vtable). – Macke Oct 15 '09 at 16:12
  • don't forget NRVO, and of course any optimization is allowed as long as it doesn't change the program output – jk. Feb 26 '10 at 09:10
  • With C++0x exception specifications are deprecated from the standard –  Oct 04 '11 at 16:58
26

You can access protected data and function members of any class, without undefined behavior, and with expected semantics. Read on to see how. Read also the defect report about this.

Normally, C++ forbids you to access non-static protected members of a class's object, even if that class is your base class

struct A {
protected:
    int a;
};

struct B : A {
    // error: can't access protected member
    static int get(A &x) { return x.a; }
};

struct C : A { };

That's forbidden: You and the compiler don't know what the reference actually points at. It could be a C object, in which case class B has no business and clue about its data. Such access is only granted if x is a reference to a derived class or one derived from it. And it could allow arbitrary piece of code to read any protected member by just making up a "throw-away" class that reads out members, for example of std::stack:

void f(std::stack<int> &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack<int> {
        static std::deque<int> &get(std::stack<int> &s) {
            // error: stack<int>::c is protected
            return s.c;
        }
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque<int> &d = pillager::get(s);
}

Surely, as you see this would cause way too much damage. But now, member pointers allow circumventing this protection! The key point is that the type of a member pointer is bound to the class that actually contains said member - not to the class that you specified when taking the address. This allows us to circumvent checking

struct A {
protected:
    int a;
};

struct B : A {
    // valid: *can* access protected member
    static int get(A &x) { return x.*(&B::a); }
};

struct C : A { };

And of course, it also works with the std::stack example.

void f(std::stack<int> &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack<int> {
        static std::deque<int> &get(std::stack<int> &s) {
            return s.*(pillager::c);
        }
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque<int> &d = pillager::get(s);
}

That's going to be even easier with a using declaration in the derived class, which makes the member name public and refers to the member of the base class.

void f(std::stack<int> &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack<int> {
        using std::stack<int>::c;
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque<int> &d = s.*(&pillager::c);
}
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
26

Hidden features:

  1. Pure virtual functions can have implementation. Common example, pure virtual destructor.
  2. If a function throws an exception not listed in its exception specifications, but the function has std::bad_exception in its exception specification, the exception is converted into std::bad_exception and thrown automatically. That way you will at least know that a bad_exception was thrown. Read more here.

  3. function try blocks

  4. The template keyword in disambiguating typedefs in a class template. If the name of a member template specialization appears after a ., ->, or :: operator, and that name has explicitly qualified template parameters, prefix the member template name with the keyword template. Read more here.

  5. function parameter defaults can be changed at runtime. Read more here.

  6. A[i] works as good as i[A]

  7. Temporary instances of a class can be modified! A non-const member function can be invoked on a temporary object. For example:

    struct Bar {
      void modify() {}
    }
    int main (void) {
      Bar().modify();   /* non-const function invoked on a temporary. */
    }
    

    Read more here.

  8. If two different types are present before and after the : in the ternary (?:) operator expression, then the resulting type of the expression is the one that is the most general of the two. For example:

    void foo (int) {}
    void foo (double) {}
    struct X {
      X (double d = 0.0) {}
    };
    void foo (X) {} 
    
    int main(void) {
      int i = 1;
      foo(i ? 0 : 0.0); // calls foo(double)
      X x;
      foo(i ? 0.0 : x);  // calls foo(X)
    }
    
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Sumant
  • 4,286
  • 1
  • 23
  • 31
  • P Daddy: A[i] == *(A+i) == *(i+A) == i[A] – abelenky Jan 07 '09 at 22:08
  • I get the commutation, it's just that this means that [] has no semantic value of its own and is simply equivalent to a macro-style replacement where "x[y]" is replaced with "(*((x) + (y)))". Not at all what I expected. I wonder why it's defined this way. – P Daddy Jan 08 '09 at 03:07
  • Backward compatibility with C – jmucchiello Jan 19 '09 at 08:05
  • 2
    Regarding your first point: There's one particular case where you *have to* implement a pure virtual function: pure virtual destructors. – Frerich Raabe Oct 30 '09 at 14:56
26

Another hidden feature is that you can call class objects that can be converted to function pointers or references. Overload resolution is done on the result of them, and arguments are perfectly forwarded.

template<typename Func1, typename Func2>
class callable {
  Func1 *m_f1;
  Func2 *m_f2;

public:
  callable(Func1 *f1, Func2 *f2):m_f1(f1), m_f2(f2) { }
  operator Func1*() { return m_f1; }
  operator Func2*() { return m_f2; }
};

void foo(int i) { std::cout << "foo: " << i << std::endl; }
void bar(long il) { std::cout << "bar: " << il << std::endl; }

int main() {
  callable<void(int), void(long)> c(foo, bar);
  c(42); // calls foo
  c(42L); // calls bar
}

These are called "surrogate call functions".

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    When you say overload resolution is done on the result of them, do you mean it actually converts it to both Functors and then does overload resolution? I tried printing something in operator Func1* (), and operator Func2* (), but it seems to pick the correct one when it figures out which conversion operator to invoke. – navigator Jul 08 '10 at 11:32
  • 3
    @navigator, yep it conceptually converts to both and then picks the best. It does not need to actually call them, because it knows from the result-type what they will yield already. The actual call is done when it turns out what was finally picked. – Johannes Schaub - litb Jul 08 '10 at 18:51
24

map::operator[] creates entry if key is missing and returns reference to default-constructed entry value. So you can write:

map<int, string> m;
string& s = m[42]; // no need for map::find()
if (s.empty()) { // assuming we never store empty values in m
  s.assign(...);
}
cout << s;

I'm amazed at how many C++ programmers don't know this.

Constantin
  • 27,478
  • 10
  • 60
  • 79
  • 11
    And on the opposite end you cannot use operator[] on a const map – David Rodríguez - dribeas Jan 03 '09 at 15:22
  • 2
    +1 for Nick, people can go insane if they don't know about `.find()`. – LiraNuna Sep 09 '09 at 22:19
  • or "`const map::operator[]` generates error messages" – just somebody Dec 27 '09 at 20:54
  • 2
    Not a feature of the language, it is a feature of the Standard template library. It is also pretty obvious, since operator[] returns a valid reference. – Ramon Zarazua B. Feb 26 '10 at 09:01
  • It still does bite people: "map m -> if (m[i] == 0) return; /* Not found */" is an insidious memory leak. – Lars Mar 15 '10 at 23:25
  • 2
    I had to use maps in C# for while, where maps don't behave that way, in order to realize that this is a feature. I thought I was annoyed by it more than I used it, but it seems I was wrong. I'm missing it in C#. – sbi Sep 20 '10 at 07:47
  • Once before knowing much about C++ containers, I've already used PHP associative arrays a lot. With that background, it was the exact opposite surpise. In fact it was quite surprising to me that there is no `V operator[] (K) const`. – Sebastian Mach Jul 21 '11 at 12:12
20

Putting functions or variables in a nameless namespace deprecates the use of static to restrict them to file scope.

Jim Hunziker
  • 14,111
  • 8
  • 58
  • 64
  • "deprecates" is a strong term… – Potatoswatter Feb 26 '10 at 09:37
  • @Potato: Old comment, I know, but the standard does say the use of static in namespace scope is deprecated, with preference for unnamed namespaces. – GManNickG Apr 21 '10 at 05:27
  • @GMan: no prob, I don't think SO pages really "die." Just for both sides of the story, `static` in global scope is not deprecated in any way. (For reference: C++03 §D.2) – Potatoswatter Apr 21 '10 at 05:39
  • Ah, on closer reading, "A name declared in the global namespace has global namespace scope (also called global scope)." Does that really mean that? – Potatoswatter Apr 21 '10 at 05:46
  • @Potato: Yup. :) `static` use should only be used within a class-type or function. – GManNickG Apr 21 '10 at 06:02
19

Defining ordinary friend functions in class templates needs special attention:

template <typename T> 
class Creator { 
    friend void appear() {  // a new function ::appear(), but it doesn't 
        …                   // exist until Creator is instantiated 
    } 
};
Creator<void> miracle;  // ::appear() is created at this point 
Creator<double> oops;   // ERROR: ::appear() is created a second time! 

In this example, two different instantiations create two identical definitions—a direct violation of the ODR

We must therefore make sure the template parameters of the class template appear in the type of any friend function defined in that template (unless we want to prevent more than one instantiation of a class template in a particular file, but this is rather unlikely). Let's apply this to a variation of our previous example:

template <typename T> 
class Creator { 
    friend void feed(Creator<T>*){  // every T generates a different 
        …                           // function ::feed() 
    } 
}; 

Creator<void> one;     // generates ::feed(Creator<void>*) 
Creator<double> two;   // generates ::feed(Creator<double>*) 

Disclaimer: I have pasted this section from C++ Templates: The Complete Guide / Section 8.4

Özgür
  • 8,077
  • 2
  • 68
  • 66
18

void functions can return void values

Little known, but the following code is fine

void f() { }
void g() { return f(); }

Aswell as the following weird looking one

void f() { return (void)"i'm discarded"; }

Knowing about this, you can take advantage in some areas. One example: void functions can't return a value but you can also not just return nothing, because they may be instantiated with non-void. Instead of storing the value into a local variable, which will cause an error for void, just return a value directly

template<typename T>
struct sample {
  // assume f<T> may return void
  T dosomething() { return f<T>(); }

  // better than T t = f<T>(); /* ... */ return t; !
};
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
17

Read a file into a vector of strings:

 vector<string> V;
 copy(istream_iterator<string>(cin), istream_iterator<string>(),
     back_inserter(V));

istream_iterator

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
14

You can template bitfields.

template <size_t X, size_t Y>
struct bitfield
{
    char left  : X;
    char right : Y;
};

I have yet to come up with any purpose for this, but it sure as heck surprised me.

Kaz Dragon
  • 6,681
  • 2
  • 36
  • 45
  • 1
    See here, where I recently suggested it for n-bit arithmetic: http://stackoverflow.com/questions/8309538/integer-subtraction-with-wrap-around-for-n-bits/8309592#8309592 – sehe Dec 04 '11 at 01:08
14

One of the most interesting grammars of any programming languages.

Three of these things belong together, and two are something altogether different...

SomeType t = u;
SomeType t(u);
SomeType t();
SomeType t;
SomeType t(SomeType(u));

All but the third and fifth define a SomeType object on the stack and initialize it (with u in the first two case, and the default constructor in the fourth. The third is declaring a function that takes no parameters and returns a SomeType. The fifth is similarly declaring a function that takes one parameter by value of type SomeType named u.

Eclipse
  • 44,851
  • 20
  • 112
  • 171
  • is there any difference between 1st and 2nd? though, I know they are both initializations. – Özgür Jan 07 '09 at 20:53
  • Comptrol: I don't think so. Both will end up calling the copy-constructor, even though the first one LOOKS like the assignment operator, it is really the copy-constructor. – abelenky Jan 07 '09 at 22:05
  • 1
    If u is a different type from SomeType, then the first one will call the conversion constructor first and then the copy constructor, whereas the second one will only call the conversion constructor. – Eclipse Jan 07 '09 at 23:32
  • 3
    1st is implicit call of constructor, 2nd is explicit call. Look at the following code to see the difference: #include class sss { public: explicit sss( int ) { std::cout << "int" << std::endl; }; sss( double ) { std::cout << "double" << std::endl; }; }; int main() { sss ddd( 7 ); // calls int constructor sss xxx = 7; // calls double constructor return 0; } – Kirill V. Lyadvinsky Jun 23 '09 at 20:04
  • True - the first line will not work if the constructor is declared explicit. – Eclipse Jun 23 '09 at 20:43
  • Otherwise known as: The most vexxing parse. "Fixed" in C++0x with new syntax: SomeType t{SomeType{u}} – mmocny Mar 05 '11 at 16:32
12

Getting rid of forward declarations:

struct global
{
     void main()
     {
           a = 1;
           b();
     }
     int a;
     void b(){}
}
singleton;

Writing switch-statements with ?: operators:

string result = 
    a==0 ? "zero" :
    a==1 ? "one" :
    a==2 ? "two" :
    0;

Doing everything on a single line:

void a();
int b();
float c = (a(),b(),1.0f);

Zeroing structs without memset:

FStruct s = {0};

Normalizing/wrapping angle- and time-values:

int angle = (short)((+180+30)*65536/360) * 360/65536; //==-150

Assigning references:

struct ref
{
   int& r;
   ref(int& r):r(r){}
};
int b;
ref a(b);
int c;
*(int**)&a = &c;
AareP
  • 2,355
  • 3
  • 21
  • 28
  • 2
    `FStruct s = {};` is even shorter. – Constantin Oct 05 '08 at 17:43
  • In the last example, it would be simpler with: a(); b(); float c=1.0f; – Zifre Apr 15 '09 at 23:48
  • @Zifre: the trick is exactly the last line **float c = (a(),b(),1.0f);** - putting everything that is closed by a semiclon in one line is no trick at all. But be careful: **int d = (a(),b(),1.0f);** would get the value of b! – fmuecke Nov 19 '09 at 12:57
  • 2
    This syntax "float c=(a(),b(),1.0f);" is useful for accenting the assigment-operation (assigment of "c"). Assigment-operations are important in programming because they are less likely to become deprecated IMO. Don't know why, might be something to do with functional programming where program state is re-assigned every frame. PS. And no, "int d = (11,22,1.0f)" will be equal to "1". Tested a minute ago with VS2008. – AareP Nov 19 '09 at 17:29
  • 2
    +1 Shouldn't you be _calling_ `main`? I'd suggest `global().main();` and just forget about the singleton (_you can just work with the temporary, which gets it's lifetime extended_) – sehe Dec 04 '11 at 01:40
  • 1
    I doubt assigning references is portable. I love the struct to waive forward declarations though. – Thomas Eding Feb 23 '12 at 18:13
12

The ternary conditional operator ?: requires its second and third operand to have "agreeable" types (speaking informally). But this requirement has one exception (pun intended): either the second or third operand can be a throw expression (which has type void), regardless of the type of the other operand.

In other words, one can write the following pefrectly valid C++ expressions using the ?: operator

i = a > b ? a : throw something();

BTW, the fact that throw expression is actually an expression (of type void) and not a statement is another little-known feature of C++ language. This means, among other things, that the following code is perfectly valid

void foo()
{
  return throw something();
}

although there's not much point in doing it this way (maybe in some generic template code this might come handy).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • For what it's worth, Neil has a question on this: http://stackoverflow.com/questions/1212978/in-c-if-throw-is-an-expression-what-is-its-type , just for extra info. – GManNickG Feb 26 '10 at 07:09
12

The dominance rule is useful, but little known. It says that even if in a non-unique path through a base-class lattice, name-lookup for a partially hidden member is unique if the member belongs to a virtual base-class:

struct A { void f() { } };

struct B : virtual A { void f() { cout << "B!"; } };
struct C : virtual A { };

// name-lookup sees B::f and A::f, but B::f dominates over A::f !
struct D : B, C { void g() { f(); } };

I've used this to implement alignment-support that automatically figures out the strictest alignment by means of the dominance rule.

This does not only apply to virtual functions, but also to typedef names, static/non-virtual members and anything else. I've seen it used to implement overwritable traits in meta-programs.

Community
  • 1
  • 1
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
9

I found this blog to be an amazing resource about the arcanes of C++ : C++ Truths.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Drealmer
  • 5,578
  • 3
  • 30
  • 37
8

Local classes are awesome :

struct MyAwesomeAbstractClass
{ ... };


template <typename T>
MyAwesomeAbstractClass*
create_awesome(T param)
{
    struct ans : MyAwesomeAbstractClass
    {
        // Make the implementation depend on T
    };

    return new ans(...);
}

quite neat, since it doesn't pollute the namespace with useless class definitions...

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
8

A dangerous secret is

Fred* f = new(ram) Fred(); http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
f->~Fred();

My favorite secret I rarely see used:

class A
{
};

struct B
{
  A a;
  operator A&() { return a; }
};

void func(A a) { }

int main()
{
  A a, c;
  B b;
  a=c;
  func(b); //yeah baby
  a=b; //gotta love this
}
Konrad
  • 39,751
  • 32
  • 78
  • 114
  • 14
    Umm, hate to say it but that's actually a not very hidden "type cast operator". Anyone who's ever looked at operator overloads probably knows about this. – Nick Bedford Mar 26 '10 at 00:49
  • The lead programmers at my work didnt know about it. Only one person i have met knew about it. Also i seen tutorials that do not mention it including my favorite tutorial http://www.cplusplus.com/doc/tutorial/ –  Mar 26 '10 at 18:15
7

Primitive types have constructors.

int i(3);

works.

  • 6
    That's not a constructor, that's just a form of initialization, namely *direct initialization*. Primitive types do not have constructors. – GManNickG Jan 06 '11 at 23:16
  • @Midas: it initialized `i` with the value `3`. This syntax is allows for uniformity with user-defined types, which is especially useful in templates. – André Caron May 21 '11 at 14:14
7

One hidden feature, even hidden to the GCC developers, is to initialize an array member using a string literal. Suppose you have a structure that needs to work with a C array, and you want to initialize the array member with a default content

struct Person {
  char name[255];
  Person():name("???") { }
};

This works, and only works with char arrays and string literal initializers. No strcpy is needed!

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Maybe it's just me, but this seems obvious, given that `void foo(){char p[255] = "daddy";}` is also a legal way to initialize an array. – P Daddy Jul 08 '10 at 21:11
  • @PDaddy, it's not too obvious, because while the `= "foo"` thing is often done in code, it's hardly never done for member initializers. I have never seen it before, until i read the Standard and found it is allowed and works with other compilers. – Johannes Schaub - litb Jul 08 '10 at 21:17
  • Not trying to be argumentative, but as a beginner, this was the next thing that came to mind after trying something like `class C{char p[255] = "daddy";};` and getting "only static const integral data members can be initialized with a class". But at the time, I had just recently learned of initialization lists, so perhaps that made it easier. In any case, this is certainly a clear example of how initialization lists are different from assignment within the constructor body. – P Daddy Jul 09 '10 at 00:55
6

One example out of many: template metaprogramming. Nobody in the standards committee intended there to be a Turing-complete sublanguage that gets executed at compile-time.

Template metaprogramming is hardly a hidden feature. It's even in the boost library. See MPL. But if "almost hidden" is good enough, then take a look at the boost libraries. It contain many goodies which are not easy accesible without the backing of a strong library.

One example is boost.lambda library, which is interesting since C++ does not have lambda functions in the current standard.

Another example is Loki, which "makes extensive use of C++ template metaprogramming and implements several commonly used tools: typelist, functor, singleton, smart pointer, object factory, visitor and multimethods." [Wikipedia]

Markowitch
  • 26
  • 1
  • 3
    Template metaprogramming isn't hidden anymore because it was so useful. However, it's hidden in the way that the feature is not designed into C++ but rather turned up by coincidence. – Konrad Rudolph Sep 17 '08 at 09:30
5

There is no hidden features, but the language C++ is very powerful and frequently even developers of standard couldn't imagine what C++ can be used for.

Actually from simple enough language construction you can write something very powerful. A lot of such things are available at www.boost.org as an examples (and http://www.boost.org/doc/libs/1_36_0/doc/html/lambda.html among them).

To understand the way how simple language constuction can be combined to something powerful it is good to read "C++ Templates: The Complete Guide" by David Vandevoorde, Nicolai M. Josuttis and really magic book "Modern C++ Design ... " by Andrei Alexandrescu.

And finally, it is difficult to learn C++, you should try to fill it ;)

sergtk
  • 10,714
  • 15
  • 75
  • 130
4

It seems to me that only few people know about unnamed namespaces:

namespace {
  // Classes, functions, and objects here.
}

Unnamed namespaces behave as if they was replaced by:

namespace __unique_name__ { /* empty body */ }
using namespace __unique_name__;
namespace __unique_name__ {
  // original namespace body
}

".. where all occurances of [this unique name] in a translation unit are replaced by the same identifier and this identifier differs from all other identifiers in the entire program." [C++03, 7.3.1.1/1]

vobject
  • 5,290
  • 3
  • 29
  • 21
  • Unfortunately, using an anon namespace alone still leaves external (though unreferenceable) symbols in your final link. Until this changes, if you care about final binary size, its best to declare any file local functions and variable static as well. – Jon Oct 27 '09 at 18:09
  • @Jon: And what's the difference after you strip the executables? –  Feb 26 '10 at 08:24
4

Is it possible for C++ template to check for a function’s existence?

Community
  • 1
  • 1
Özgür
  • 8,077
  • 2
  • 68
  • 66
3

throw is an expression

sdcvvc
  • 25,343
  • 4
  • 66
  • 102
3

From C++ Truths.

Defining functions having identical signatures in the same scope, so this is legal:

template<class T> // (a) a base template
void f(T) {
  std::cout << "f(T)\n";
}

template<>
void f<>(int*) { // (b) an explicit specialization
  std::cout << "f(int *) specilization\n";
}

template<class T> // (c) another, overloads (a)
void f(T*) {
  std::cout << "f(T *)\n";
}

template<>
void f<>(int*) { // (d) another identical explicit specialization
  std::cout << "f(int *) another specilization\n";
}
Özgür
  • 8,077
  • 2
  • 68
  • 66
  • 3
    +1 for obscurity, though you yourself are obscuring things by omitting the fact the above code needs 2 more function template declarations (1 at the start, 1 in between) to compile. – j_random_hacker Jan 22 '09 at 09:28
3

I'm not sure about hidden, but there are some interesting 'tricks' that probably aren't obvious from just reading the spec.

neuroguy123
  • 1,355
  • 10
  • 14
  • Even though older by 55 mins, should be merged/combined with the duplicate at http://stackoverflow.com/questions/75538/hidden-features-of-c/76058#76058, or just deleted in favor of the other. –  Feb 26 '10 at 08:43
  • Please... PLEASE do not use Duff's Device. – Billy ONeal Jul 04 '10 at 20:48
3

There are a lot of "undefined behavior". You can learn how to avoid them reading good books and reading the standards.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ugasoft
  • 3,778
  • 7
  • 27
  • 23
  • 2
    How is this a feature? There are two different ways of considering it as a feature, but I see no indication of either here. -1 for being vague. –  Feb 26 '10 at 08:44
  • Or you can learn to embrace them, which is a Good Thing. – Thomas Eding Feb 23 '12 at 18:29
3

Most C++ developers ignore the power of template metaprogramming. Check out Loki Libary. It implements several advanced tools like typelist, functor, singleton, smart pointer, object factory, visitor and multimethods using template metaprogramming extensively (from wikipedia). For most part you could consider these as "hidden" c++ feature.

Sridhar Iyer
  • 2,772
  • 1
  • 21
  • 28
  • We don't ignore it, we shun it.... – Jimmy J Mar 23 '09 at 20:26
  • Duplicate of template metaprogramming from http://stackoverflow.com/questions/75538/hidden-features-of-c/76058#76058. These examples merged into that answer so this duplicate can be deleted. –  Feb 26 '10 at 08:35
3
  • pointers to class methods
  • The "typename" keyword
shoosh
  • 76,898
  • 55
  • 205
  • 325
2

main() does not need a return value:

int main(){}

is the shortest valid C++ program.

Thomas Eding
  • 35,312
  • 13
  • 75
  • 106
Jeffrey Faust
  • 547
  • 3
  • 12
2
  1. map::insert(std::pair(key, value)); doesn't overwrite if key value already exists.

  2. You can instantiate a class right after its definition: (I might add that this feature has given me hundreds of compilation errors because of the missing semicolon, and I've never ever seen anyone use this on classes)

    class MyClass {public: /* code */} myClass;
    
Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
2

Pay attention to difference between free function pointer and member function pointer initializations:

member function:

struct S
{
 void func(){};
};
int main(){
void (S::*pmf)()=&S::func;//  & is mandatory
}

and free function:

void func(int){}
int main(){
void (*pf)(int)=func; // & is unnecessary it can be &func as well; 
}

Thanks to this redundant &, you can add stream manipulators-which are free functions- in chain without it:

cout<<hex<<56; //otherwise you would have to write cout<<&hex<<56, not neat.
Özgür
  • 8,077
  • 2
  • 68
  • 66
1

I find recursive template instatiations pretty cool:

template<class int>
class foo;

template
class foo<0> {
    int* get<0>() { return array; }
    int* array;  
};

template<class int>
class foo<i> : public foo<i-1> {
    int* get<i>() { return array + 1; }  
};

I've used that to generate a class with 10-15 functions that return pointers into various parts of an array, since an API I used required one function pointer for each value.

I.e. programming the compiler to generate a bunch of functions, via recursion. Easy as pie. :)

Macke
  • 24,812
  • 7
  • 82
  • 118
1

If operator delete() takes size argument in addition to *void, that means it will, highly, be a base class. That size argument render possible checking the size of the types in order to destroy the correct one. Here what Stephen Dewhurst tells about this:

Notice also that we've employed a two-argument version of operator delete rather than the usual one-argument version. This two-argument version is another "usual" version of member operator delete often employed by base classes that expect derived classes to inherit their operator delete implementation. The second argument will contain the size of the object being deleted—information that is often useful in implementing custom memory management.

Özgür
  • 8,077
  • 2
  • 68
  • 66
1

Indirect Conversion Idiom:

Suppose you're designing a smart pointer class. In addition to overloading the operators * and ->, a smart pointer class usually defines a conversion operator to bool:

template <class T>
class Ptr
{
public:
 operator bool() const
 {
  return (rawptr ? true: false);
 }
//..more stuff
private:
 T * rawptr;
};

The conversion to bool enables clients to use smart pointers in expressions that require bool operands:

Ptr<int> ptr(new int);
if(ptr ) //calls operator bool()
 cout<<"int value is: "<<*ptr <<endl;
else
 cout<<"empty"<<endl;

Furthermore, the implicit conversion to bool is required in conditional declarations such as:

if (shared_ptr<X> px = dynamic_pointer_cast<X>(py))
{
 //we get here only of px isn't empty
} 

Alas, this automatic conversion opens the gate to unwelcome surprises:

Ptr <int> p1;
Ptr <double> p2;

//surprise #1
cout<<"p1 + p2 = "<< p1+p2 <<endl; 
//prints 0, 1, or 2, although there isn't an overloaded operator+()

Ptr <File> pf;
Ptr <Query> pq; // Query and File are unrelated 

//surprise #2
if(pf==pq) //compares bool values, not pointers! 

Solution: Use the "indirect conversion" idiom, by a conversion from pointer to data member[pMember] to bool so that there will be only 1 implicit conversion, which will prevent aforementioned unexpected behaviour: pMember->bool rather that bool->something else.

Özgür
  • 8,077
  • 2
  • 68
  • 66
  • but also see **[`safe bool idiom`](http://www.artima.com/cppsource/safebool.html)** – sehe Dec 04 '11 at 02:01
1

There are tons of "tricky" constructs in C++. They go from "simple" implementions of sealed/final classes using virtual inheritance. And get to pretty "complex" meta programming constructs such as Boost's MPL (tutorial). The possibilities for shooting yourself in the foot are endless, but if kept in check (i.e. seasoned programmers), provide some of the best flexibility in terms of maintainability and performance.

Amir
  • 4,131
  • 26
  • 36
1

The class and struct class-keys are nearly identical. The main difference is that classes default to private access for members and bases, while structs default to public:

// this is completely valid C++:
class A;
struct A { virtual ~A() = 0; };
class B : public A { public: virtual ~B(); };

// means the exact same as:
struct A;
class A { public: virtual ~A() = 0; };
struct B : A { virtual ~B(); };

// you can't even tell the difference from other code whether 'struct'
// or 'class' was used for A and B

Unions can also have members and methods, and default to public access similarly to structs.

a_m0d
  • 12,034
  • 15
  • 57
  • 79
0

Member pointers and member pointer operator ->*

#include <stdio.h>
struct A { int d; int e() { return d; } };
int main() {
    A* a = new A();
    a->d = 8;
    printf("%d %d\n", a ->* &A::d, (a ->* &A::e)() );
    return 0;
}

For methods (a ->* &A::e)() is a bit like Function.call() from javascript

var f = A.e
f.call(a) 

For members it's a bit like accessing with [] operator

a['d']
Kamil Szot
  • 17,436
  • 6
  • 62
  • 65
0

My favorite (for the time being) is the lack of sematics in a statement like A=B=C. What the value of A is basically undetermined.

Think of this:

class clC
{
public:
   clC& operator=(const clC& other)
   {
      //do some assignment stuff
      return copy(other);
   }
   virtual clC& copy(const clC& other);
}

class clB : public clC
{
public:
  clB() : m_copy()
  {
  }

  clC& copy(const clC& other)
  {
    return m_copy;
  }

private:
  class clInnerB : public clC
  {
  }
  clInnerB m_copy;
}

now A might be of a type inaccessible to any other than objects of type clB and have a value that's unrelated to C.

Rune FS
  • 21,497
  • 7
  • 62
  • 96
  • huh - you're basically saying that you can use overloading to change semantics? Now, if you were to demonstrate how the semantics of `a=b=c` wasn't fixed even for builtin types/operators... That would be interesting. **§ 3.10** _For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types._ – sehe Dec 04 '11 at 02:10
  • @sehe how about an overload for int to always assign say 1/3 of c to a in a=b=c? – Rune FS Dec 04 '11 at 19:05
  • how will you define the _non static member_ `operator=` on the _class_ (sic) `int`? – sehe Dec 04 '11 at 21:43
  • @sehe never said I would – Rune FS Dec 05 '11 at 10:04
  • `how about an overload for int to always assign say 1/3 of c to a in a=b=c?` doesn't materialize into legal code for me. Could you show what it is that you _mean_? You claiming a `lack of semantics` as _hidden feature_ of the C++ language. I think it makes sense that you explain what you meant? – sehe Dec 05 '11 at 10:13
  • @sehe are you claiming that the semantics for the assignment operator _is_ fixed in c++? that you can reason (with certainty) what a will be assigned related to b and c in the statement a=b=c? – Rune FS Dec 06 '11 at 10:27
  • Oh. That's anticlimactic then. I thought you were somehow suggesting that is was 'under-spec-ed' and a hidden feature. Obviously it is by design. Without this notion there would be no such thing as [expression templates](http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Expression-template), so no Blitz++, Eigen, Boost Proto (heck, 25% of boost) etc. etc. Also, would you say the same about C# then? https://ideone.com/6dxZG – sehe Dec 06 '11 at 10:48
  • Semantics **are fixed** for builtin types. You can also reason about it for custom types, rigidly and formally. (_If `operator=` takes a `const&`, there is no way the value will become clobbered_). Your opening sentence is just way too broad: `the lack of sematics in a statement like A=B=C`. Not just any statement: a statement involving _types with non-standard semantics_. Well doh? Also that is not a lack of semantics, that is an abundance of possibility. (The former suggests a language flaw) – sehe Dec 06 '11 at 10:57
  • that any given operator can mean any given thing is by definition lack of semantics. Yes it might create an abundance of possibility but lack of mean is lack of meaning – Rune FS Dec 09 '11 at 09:42
0

You can view all the predefined macros through command-line switches with some compilers. This works with gcc and icc (Intel's C++ compiler):

$ touch empty.cpp
$ g++ -E -dM empty.cpp | sort >gxx-macros.txt
$ icc -E -dM empty.cpp | sort >icx-macros.txt
$ touch empty.c
$ gcc -E -dM empty.c | sort >gcc-macros.txt
$ icc -E -dM empty.c | sort >icc-macros.txt

For MSVC they are listed in a single place. They could be documented in a single place for the others too, but with the above commands you can clearly see what is and isn't defined and exactly what values are used, after applying all of the other command-line switches.

Compare (after sorting):

 $ diff gxx-macros.txt icx-macros.txt
 $ diff gxx-macros.txt gcc-macros.txt
 $ diff icx-macros.txt icc-macros.txt
0
class Empty {};

namespace std {
  // #1 specializing from std namespace is okay under certain circumstances
  template<>
  void swap<Empty>(Empty&, Empty&) {} 
}

/* #2 The following function has no arguments. 
   There is no 'unknown argument list' as we do
   in C.
*/
void my_function() { 
  cout << "whoa! an error\n"; // #3 using can be scoped, as it is in main below
  // and this doesn't affect things outside of that scope
}

int main() {
  using namespace std; /* #4 you can use using in function scopes */
  cout << sizeof(Empty) << "\n"; /* #5 sizeof(Empty) is never 0 */
  /* #6 falling off of main without an explicit return means "return 0;" */
}
dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • 3
    No, extending std is absolutely *not* OK, and the standard explicitly forbids it (with one exception: overloads of `swap`). – Konrad Rudolph Feb 21 '09 at 12:40
  • Thanks. I was misguided. But is it just swap or does the standard say: Only specialisations of standard templates? – dirkgently Feb 21 '09 at 12:54
  • 4
    It's allowed to specialize templates within `std`, as long as the specialization depends on a user defined type. It's not restricted to swap. – Johannes Schaub - litb Oct 15 '09 at 11:15
  • 1
    Your specific example however is invalid, because your specialization doesn't match any function template signature. You would have to have two reference parameters etc :) – Johannes Schaub - litb Oct 15 '09 at 11:16
  • 1
    "It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified." (17.4.3.1/1) You can't overload std::swap, etc., but you can specialize them: "A program may add template specializations for any standard library template to namespace std. Such a specialization ... results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template." (17.4.3.1/1) –  Feb 26 '10 at 07:48
  • 1
    Note that std::swap, in particular, cannot be partially specialized (it is a function) and cannot be overloaded (see above standard quote), so you must do something else for templates you write. Example of how to use ADL with std::swap at http://stackoverflow.com/questions/2197141/why-template-specialization-is-important-and-necessary-in-c/2197682#2197682. –  Feb 26 '10 at 07:51
  • @Konrad: Where is that exception specified? I don't believe it exists. –  Feb 26 '10 at 07:56
  • @Roger, you're right. I meant specialize, not overload. – Konrad Rudolph Feb 27 '10 at 15:36
0

Adding constraints to templates.

Community
  • 1
  • 1
Özgür
  • 8,077
  • 2
  • 68
  • 66
-1

Emulating reinterpret cast with static cast :

int var;
string *str = reinterpret_cast<string*>(&var);

the above code is equivalent to following:

int var;    
string *str = static_cast<string*>(static_cast<void*>(&var));
Özgür
  • 8,077
  • 2
  • 68
  • 66
  • What would be the point of that? – Zifre Apr 15 '09 at 23:50
  • Zifre, nothing. but the result is the same in both cases. see here: http://www.informit.com/blogs/blog.aspx?uk=30-C-Tips-in-30-Days-Tip-4-Using-staticcast-instead-of-reinterpretcast – Özgür Apr 16 '09 at 00:14
  • I really don't see the "trick" to this, as your second example is basically just describing what happens with a reinterpret_cast. You could have also done this: string *str = (string*)(void*)(&var); Also, shouldn't your static_cast be static_cast? – Jared Jun 22 '09 at 04:02
  • @Jared, There is no trick. I just didn't know the inner workings of reinterpret_cast and wanted to share it. You don't even need to add (void*) , after all C style casting encompasses both reinterpret_cast and static_cast. you are right about void*, thanks. – Özgür Jun 22 '09 at 07:36
  • 4
    This isn't true. The double static cast is what people typically *think* reinterpret_cast does. But it doesn't. They're not equivalent. static_cast guarantees that it'll yield a pointer to the same address. reinterpret_cast just provides an implementation-defined mapping. – jalf Sep 23 '09 at 13:00
  • 2
    `static_cast` only guarantees the same address if you cast back to the same type that you had before converting to `void*`. There is some hidden mystery in the Standard about some special handling of a double `static_cast` like shown in this answer, but i yet have to see anyone proving the real existance of this special handling beyond "there is this, but i dunno where" wordings. – Johannes Schaub - litb Oct 15 '09 at 11:11
-2

Pointer arithmetics.

It's actually a C feature, but I noticed that few people that use C/C++ are really aware it even exists. I consider this feature of the C language truly shows the genius and vision of its inventor.

To make a long story short, pointer arithmetics allows the compiler to perform a[n] as *(a+n) for any type of a. As a side note, as '+' is commutative a[n] is of course equivalent to n[a].

bernardn
  • 1,701
  • 5
  • 19
  • 23
-2

Template metaprogramming is.

osgx
  • 90,338
  • 53
  • 357
  • 513
-2

Not actually a hidden feature, but pure awesomeness:

#define private public 
mihai
  • 1
  • 1
  • 4
    Its not even a feature, its simply illegal to redefine keywords. – Georg Fritzsche Jul 05 '10 at 00:46
  • Says where? Preprocessing stage is applied before keywords are even considered by the parser/lexer. You can redefine virtually EVERYTHING. – mihai Nov 12 '11 at 20:25
  • To prove it, try this: `#define while if void main() { while(1); }` – mihai Nov 12 '11 at 20:26
  • @mihai: It says so here: **§ 17.6.1.3** ad 7: `Identifiers that are keywords or operators in C++ shall not be defined as macros in C++ standard library headers.`, combined with the **[One Definition Rule](http://en.wikipedia.org/wiki/One_Definition_Rule)**. So the only way out is to _not_ include any standard library headers and not use any standard library code – sehe Dec 04 '11 at 02:21
-2

You can return a variable reference as part of a function. It has some uses, mostly for producing horrible code:

int s ;
vector <int> a ;
vector <int> b ;

int &G(int h)
{
    if ( h < a.size() ) return a[h] ;
    if ( h - a.size() < b.size() ) return b[ h - a.size() ] ;
    return s ;
}

int main()
{
    a = vector <int> (100) ;
    b = vector <int> (100) ;

    G( 20) = 40 ; //a[20] becomes 40
    G(120) = 40 ; //b[20] becomes 40
    G(424) = 40 ; //s becomes 40
}
Martín Fixman
  • 9,055
  • 9
  • 38
  • 46
-3

I know somebody who defines a getter and a setter at the same time with only one method. Like this:

class foo
{
    int x;

    int* GetX(){
        return &x;
    }
}

You can now use this as a getter as usual (well, almost):

int a = *GetX();

and as a setter:

*GetX() = 17;
aheld
  • 313
  • 1
  • 5
  • 11
  • I'd change the name though. This leads to major confusion. – Tobias Langner Feb 26 '10 at 09:04
  • He only uses it when he programs stuff for himself. – aheld Feb 26 '10 at 09:10
  • 6
    Why on earth would he return `int*` instead of `int&` in that case!? – Johann Gerell Feb 26 '10 at 09:33
  • 6
    No offense to you, aheld, but my down-vote is for your friend. :) There's no reason to have it return a pointer when a non-const reference will do. Additionally, there's no point in even having a getter, it's just a waste of space; make the member variable public. – GManNickG Feb 26 '10 at 19:40
  • It's not really a waste of space, as it's declared inline ;) – Joe D May 05 '10 at 14:37
  • 3
    It defeats the whole point of using getters and setters by exposing the internal implementation thereby making it impossible to change the implementation later on without affecting every caller. Your friend managed to combine all the disadvantages of direct member access with all the disadvantages of getters/setters. Good work. – Ferruccio Nov 18 '10 at 23:57
  • @Ferruccio: and you forgot to mention lifetime issues because of returned reference/pointers to members.. Truly awesomely bad code it is. – sehe Dec 04 '11 at 02:17