share
Stack OverflowWhat is the most spectacular way to shoot yourself in the foot with C++?
[+43] [58] TonJ
[2008-10-06 15:56:24]
[ c++ polls ]
[ http://stackoverflow.com/questions/174892] [DELETED]

In 1986 or so, Bjarne Stroustrup famously said: "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off."

What is, in your opinion, the most spectacular way to blow your leg off in C++? Points for originality, and for helpfulness.

Do the things some compilers warn about (and some others don't) count as an answer? - Milan Babuškov
If some compilers don't warn about it and generate code that does something not at all what you expected, certainly! - TonJ
(2) Man I hate that questions like this get closed. This contains my favorit discussion ever on SO (replies to my answer). I'll vote to reopen even though it won't take. - Bill K
[+57] [2008-10-07 03:13:13] Michael Easter

Originality, eh? Well how about Multi-Dimensional Analog Literals

Tighten your seatbelt and click here [1]

There is real code behind these (see bottom of post). I only wish I had an ounce of that much creativity.

Example:

  unsigned int c = ( o-----o
                     |     !
                     !     !
                     !     !
                     o-----o ).area;

  assert( c == (I-----I) * (I-------I) );
[1] http://www.xs4all.nl/~weegen/eelis/analogliterals.xhtml

(2) Very nice one. I'm going to use analog literals in my code from now on! :) - Eduardo León
Has anyone ever put this to legitimate use? That is certainly interesting... - Mr. Shickadance
(1) Holy crap! I had to look thrice before I could parse that example. - Kawa
(2) Nice! I wonder was that programmer one day like "hey! I want to have some compilable 3D ascii graphics in my code"... :) - AareP
Holy crap, this isn't a joke! That's terrifying and fantastic at the same time! O_o - DoctaJonez
(1) In what way is this shooting yourself in the foot, exactly? - Lightness Races in Orbit
1
[+39] [2008-10-06 16:06:08] Adam Rosenfield

Attempting to call a pure virtual function from a constructor or destructor. Since the derived class object has not yet been constructed (or has already been destroyed), this will result in badness. The compiler will convert virtual function calls into static calls of the base class version's of the function when it can, but there is no base class version of a pure virtual function, and undefined behavior will result. This could happen if the call is indirect, say, by calling a non-virtual function which calls the virtual function.


Huh? When calling a virtual function from a non-virtual function from a ctor? Why is that undefined the vtable is still that of base, am I missing something? - Motti
The C++ standard does not require that virtual functions are implemented using vtables. So in general, any consideration that says "it will probably work because of the state of the vtable" will not be describing mandatory behaviour. "Undefined behaviour" permits your compiler to make it 'work'... - Steve Jessop
(3) WRONG : It's not undefined if there actually IS a base version of the function. And then it works perfectly as expected, even when called indirectly. Even if you don't use a vtable. The mechanism has to work the same: in Base::Base, calling a virtual foo will call Base::foo(). - MSalters
Attempting to call a derived virtual function from the constructor OF A BASE CLASS will give you grief. Say you have Base::Base(){foo();} When you call Derived::Derived(), you'll find that Base::foo() is called, not Derived::foo(). Because when Base::Base() runs, the vtable for Derived is not up. - Stéphane
(2) to add to @MSalters' excellent correction, only if the function is declared pure, behavior is undefined. This is defined in 10.4/6 in the C++ Standard. - Johannes Schaub - litb
2
[+31] [2008-10-06 16:14:55] Rob Walker

Needing to change the signature of a base class virtual function and disconnecting all the derived class overrides without any complaints from the compiler.

And I used to think that C#'s insistence on 'virtual', 'overrides', 'new' modifiers was being pedantic ...


I get around this in staticly linked projects by changing the function signature and temporarily making it abstract. Then I get different errors report for functions that implement the wrong signature then those that don't implement it at all, and I can find which ones need to be updated. - Joel Coehoorn
I agree that requiring derived classes to explicitly state they intend to override a virtual is something that should have been in the language. It also bugs me that a static declared in a class cannot have a matching static in the definition. - Michael Burr
Yup, I'm a multiple amputee on this one! - Dave Van den Eynde
You can only appreciate the goodness of C# and the badness of C++ if you have used both a lot. - romkyns
3
[+29] [2008-10-06 16:19:07] Bill the Lizard

I've initialized an array like this:

int *ip = new int(10);

Hijinks ensue when you try to use this "array" beyond index 0 (which is usually almost immediately). The problem is that the above code is the syntax to create a pointer to a new int initialized to the value 10. It only looks like the syntax for pointer to a new array of size 10.


been there, done that, bought the T-shirt! - Martin Beckett
(1) Oooh, took me a full minute to realize what the difference was. Good one! - David Thornley
4
[+26] [2008-10-06 16:02:10] Kip

Overloading of operators in general, but particularly new, new[], delete, delete[], and [].


don't forget overloading new[] and delete[] - workmad3
thanks, i'll add those too - Kip
(9) sidenote: my company has list types that overload [] so that they start at 1 instead of 0. they were written long ago by fortran gurus, and now they are pervasive in our code. gets really annoying when you have to juggle base-0 arrays and base-1 lists in the same code! - Kip
What is the problem with overloading new/delete? - leod
(4) Kip, that 1-based [] overload sounds like a candidate for thedailywtf.com :) - Jim Buck
(3) Kip, that 1-based[] overload is just hilarious, but I have to admit, its pretty creative. - Jose Vega
This is so commonly done (and very effectively) in games. Memory management is a huge issue in game programming. - Torlack
oh. And don't forget about 'placement new' - Orion Edwards
(1) overloading new and delete is a very valid thing to do, and hardly a problem. You can get a massive performance improvement using multiple fixed block size heaps. You can kill yourself this way, but generally you know you've done it immediately so your users don't get hurt. :) - gbjbaanb
(2) This is like saying 'Driving a car is dangerous so don't drive a car'. Of course if done wrong it can get pretty bad but when done right it's quite useful and indeed a valid thing to do. - Andreas Magnusson
there is nothing wrong with overloading operators... - Johannes Schaub - litb
-1, overloading operators is a valid feature, and overloading new and delete is done a lot in embedded systems. - Edan Maor
5
[+24] [2008-10-06 16:14:27] Michael McCarty

I've seen this a few times where someone used memset() inside the ctor to easily initialize all the class variables.

myClass::myClass()
{
   memset(this,0,sizeof (myClass));
}

lol. In my newbie C++ days I actually did that. Everyone told me that in C++ a class and a struct were identical, and I'd been memsetting structs in C for ages :-( - Orion Edwards
I've just thought - I do this for simple structs all the time... I wonder if others will see my code and think 'so that's how you do it' and apply it to classes? I'd best change that practice! - gbjbaanb
That line caused some of the code I was maintaining to perform inheritance incorrectly. It messes with the virtual pointer table which was pretty fun to debug. - dr_pepper
It's also not fully portable even for PODs: there is no guarantee that "all bytes 0" is a valid value representation for every built-in type, although of course in practice it is if only because compiler-writers would rather make it be than argue with their customers. - Steve Jessop
This is of course valid for PODs with only integral members (int, char, etc) and quite useful if your POD contains several large arrays of those types. Never ever use it in a class with virtual functions though... - Andreas Magnusson
(2) @gbjbaanb: In C++ there really is no difference between structs and classes (except public vs private). So if you still use memset() on a struct, and someone adds a (member function, constructor, operator) to this struct; boom there goes your foot. - TonJ
I've also seen someone fix this by changing size of the allocation to 'sizeof(myClass)-sizeof(void*)' to leave room for the vptr. - Michael McCarty
Our old codebase had this for a time. We had horrific UB that showed up years later, and it turned out that one of the members had been changed from an automatic array into a std::map. The memset of course completely ruined it. Stupid thing to do. - Lightness Races in Orbit
6
[+18] [2008-10-06 17:36:38] Richard Corden

I love C++ for the flexibility that it offers, and with the arrival of libraries such as BOOST it is becoming easier to piece together a powerful application with most of the time spent concentrating on the business logic.

However, here are some common examples where code will compile but not do what was intended.

1) Overriding Functions

class Base {
  virtual void foo () const
  {
    // Default beahviour
  }
};

class Derived : public Base {
  virtual void foo ()
  {
    // Do something useful for Derived
  }
};

It was almost certainly not the intention of the author that 'foo' in the derived class does not override the 'foo' in the base. You have to make sure your testing is really up to scratch to make sure that you can detect that Derived::foo is not being called!

2) Operators that short-cut except when they don't:

class A {};
A foo (int * i)
{
  *i = 0;
}
bool operator && (int *, A const &);

// ... lots of space between declaration and usage

void bar (int * i)
{
  if (i && foo(i))
  {
  }
}

Others have mentioned operators, but there are 4 which are especially problematic. In the above example rather than having the usual "evaluate the first operand and if true then the second" what we actually have is a function call operator&&(i, foo(i)). The first argument i and the second foo(i). Both will be evaluated (in some unspecified order) and this will result in a null pointer dereference in foo. The other operators to watch out for are, logical or (||), comma (,) and unary &.

3) Class member initialization that doesn't initialize:

class B
{
public:
  B ();
};

class A
{
public:
  ~A();

private:
  B b;
  int i;
};

The above class the non-POD member i is not initialized by the default constructor for the class. The same applies if the constructor was written as:

  A ()
  {
  }

or

  A ()
    : b ()
  {
  }

Of course - what you need is some form of static analysis tool which will catch all of these niggling problems for you! ;)


easy on the advertising man :P - Ruben Bartelink
or you could use a language that doesn't let you shoot :) - Spence
@Spence. To be fair, I think C++ doesn't deserve to be singled out with this label. I'm not suggesting that you cannot shoot yourself in the foot, the point is that you can do so in 99.9% of languages, its not specific to C++. Unless of course you want to do all your development in SparkAda! - Richard Corden
7
[+16] [2008-10-06 19:15:31] KeyserSoze

In C/C++, if you start a numeric constant with a zero, it's interpreted as octal:

int a = 123; // Decimal 123
int b = 0123; // Octal 123, decimal 83

I've never seen this result in a bug, but once when I was hand-editing a large block of data for an array, I typed leading zeros for some of the constants just to pad them to length. If none of them had an 8 or 9 (which is invalid for octal), it would have compiled cleanly and definitely would have not worked right.


(1) bitten by that one +1 - EvilTeach
Inherited from C (where it's just as much of a problem), and not specific to C++. - David Thornley
8
[+15] [2008-10-06 16:04:10] Rontologist

It doesn't happen often, but I always find this hard to track down.

if (number = 5) {
    // code
}

Turn up your compiler's warning level. It will catch it for you. - Ferruccio
Many compilers warn about his, which can help. I am personally a fan of the sometimes maligned construction if (0 == callThatCanFail()){...} despite the rough way it reads - dmckee
That happens to me a lot when switching back and forth from VB. - Ed S.
It's been a while, but can't you also do this in C? - harpo
(4) This is not C++-specific. - Andreas Magnusson
@Andreas: But it is a valid way to shoot yourself in the foot with C++ =] - mdec
@dmckee Another partial solution that complete your construction is to declare as much as possible all variables as const. In the case "number" was const, the code would not have compiled. This is why I only "malign" the "0 == number" idiom if the coder otherwise forget to use const where appliable - paercebal
The question implies that ways that you can shoot yourself in the foot that apply to both C and C++ are not valid answers, even if spectacular. - Max Howell
@mxcl - That is not how I read the question. To me it is asking for all ways to shoot oneself. This includes all valid C answers. - Rontologist
9
[+15] [2008-10-06 15:58:23] TonJ

Here on SO [1], Joel Coehoorn wrote about this example:

  if ( blah(), 5) {
   //do something
  }

"Note that the , operator could be overloaded for the return type of the blah() function (which wasn't specified), making the result non-obvious."

[1] http://stackoverflow.com/questions/149500/what-does-the-code-if-blah-5-do#149514

IMO using a comma in an expression like this is usually non-obvious anyways. - Greg Rogers
Um, yeah. Nice to be singled out :) - Joel Coehoorn
(1) If comma can be overriden to deliver unpredictable results, doesn't that make "if( bla() + 5 )" just as problematic? - Bill K
Not so much, because people at least expect to have to look up operator+ if you add an integer to some type. Overloading &&, || or comma is just plain sneaky: first because nobody expects it, and second because in the former two cases it disables short-circuiting. - Steve Jessop
@onebyone: I hadn't thought of disabling the short-circuiting. That's really really sneaky! - TonJ
(2) @Bill K: the difference is everybody knows you can override the + operator, but fewer people know you can do that to the comma operator too. I didn't know. - TonJ
10
[+15] [2008-10-07 11:45:11] fizzer

Accidentally instantiating an RAII object as a temporary, for example:

boost::mutex::scoped_lock(m_mutex);

instead of

boost::mutex::scoped_lock guard(m_mutex);

No errors, no warnings, just mysterious intermittent runtime errors.


being there, done that - Anycorn
11
[+14] [2008-10-06 16:52:56] Adam Tegen

Not initializing a pointer and then using it later.


(4) Sorry to be pedantic, but this is not specific to C++. - Max Howell
12
[+13] [2008-10-06 17:39:12] Matt Price

Programming serious C++ before you understand it. Sadly it's reputation for being an experts only language is well deserved.

Please, please, please read Effective C++ [1] before you touch production code.

[1] http://rads.stackoverflow.com/amzn/click/0321334876

13
[+13] [2008-10-06 17:41:15] Lou Franco

Returning references to temporaries. Usually this happens when you accidentally copy-construct along the way. Something like:

string MyVal()
{
  return _val;
}

string& GetVal()
{
  return MyVal();
}

14
[+13] [2008-10-06 21:39:22] Orion Edwards

While this is not foot shooting, I flipped out when I saw a really experienced C++ programmer do this:

((SomeClass*)NULL)->SomeMethod();

Which is actually perfectly fine, as long as SomeMethod doesn't access the this pointer or call any member functions (which in this case it didn't).

Still, that kind of thing is pretty much GUARANTEED to blow the leg off the next programmer that modifies that class.


(2) Makes you think why the creator of SomeMethod() didn't declare it static. This way, you'd call it as SomeClass::SomeMethod(), and all is well. - TonJ
Actually, it might be safe to call other member functions as well. After all, they'd get the same problem: it blows up the moment you need a this pointer. Could be a cast, could be a virtual call, could be anything. Even a compiler switch changed. - MSalters
The method had some code, then literally had an if( this == NULL ) return; and then some more code. Like I said, I flipped out :-) - Orion Edwards
(3) Nice job interview question: "You find the line 'if (this==NULL) return;' in some code. What could the writer of this line possibly have intended?" - TonJ
(1) Shouldn't it be static_cast<SomeClass*>(0)->SomeMethod(); - Nikolai Ruhe
Nikolai... I think you miss the point... - Orion Edwards
15
[+10] [2008-10-06 16:59:13] Adam Tegen

Not having a virtual destructor on a base class.


(1) Why dont we just spout off all the chapters in Effective C++ by Scott Meyers... :) - Steve Duitsman
There is nothing wrong with that if your Base class is not designed to be used polymorphically. - Comptrol
Oldie but a goodie :) - StackedCrooked
16
[+9] [2008-10-06 16:01:00] Jeff Mc

Overriding ::new() operator. You might have grand hopes of tracking memory leaks or logging fragmentation or whatever. It almost always turns south quickly.


17
[+8] [2008-10-06 19:56:49] dmityugov

Something to blow the whole leg for sure, with std::map for example:

...
for ( pos = c.begin(); pos != c.end(); ++pos) {
  if ( pos->second == something) c.erase( pos);
}
...

18
[+7] [2008-10-06 21:23:20] Pascal T.

Using auto_ptr not knowing (or forgeting) that the assignment operator transfers ownership

void Foo(auto_ptr<string> val)  
{  
  std::cout << *val;    
}  

int main()  
{  
  auto_ptr<std::string> a (new std::string("abc"));  

  auto_ptr<std::string> b = a;  // a is erased !  

  Foo(b);  // b is erased also !!! (always use references in method signatures with auto_ptr)  
  ...
}

And that's also why we don't refer to it as 'the equal'-operator. Assignment-operator is good in general. The transfer-ownership-operator is good for std::auto_ptr... - Andreas Magnusson
(1) Do you know that auto_ptr will be deprecated in C++0x? There'll be a new "unique_ptr<T>" that makes use of new features of the language and does not have auto_ptr's problems. - TonJ
19
[+6] [2008-10-06 17:41:50] Matt Price

Violating the Principle of least astonishment [1]. For example operator + should add things together. If you have it do subtraction it will really confuse people and cause them to make stupid mistakes. Or as Scott Meyers put is, do as the ints do.

Edit: the quote from Meyers is from Effective C++, in my copy of the 3rd edition it's in item 18 page 80. "Clients already know how types like int behave, so you should strive to have your types behave in the same way whenever reasonable...When in doubt, do as the ints do." Go read/re-read item 18 today, and be a better programmer!

[1] http://en.wikipedia.org/wiki/Principle_of_least_astonishment

I like that quote! When I Googled it, I saw quite a few mentions, but not the original. Do you know where it's from? - TonJ
@TonJ Effective C++, I think. Or "More Effective C++". Anyway, the item where he says that operator+ should return a "const Foo", because a+b = 3 is not valid for ints, so it should not be valid for your user type either. - rlerallut
20
[+6] [2008-10-06 17:37:01] Matt Price

Casting a pointer to a type that something isn't. Then calling a virtual function on that type. Depending on how "lucky" you are there may be a function at that location in the vtable that has the same parameters. I've done this where the debugger was stepping through the wrong code. Totally perplexing. If you aren't so "lucky" then it will just crash with a corrupted stack depending on the calling conventions.


I consider crashing immediately at the point of the mistake to be lucky. - Lou Franco
Agreed! The earlier the error manifest itself the better. That's a reason type safety is important. - Matt Price
21
[+5] [2008-10-06 16:14:04] Bill the Lizard

Using multiple inheritance [1] is a good way ensure that you'll have problems.

[1] http://en.wikipedia.org/wiki/Multiple_inheritance

multiple inheritance, with classes deriving from a template base class... - artificialidiot
MI's never a problem, either you have a unwieldy hierarchy .. you have ther problems than MI, or you have base classes with same-named members (and you have to disambiguate them, not too hard), or you have different-named members... and that just works. MI is only hard for compiler writers. - gbjbaanb
MI is not the problem. If there's a problem with MI, it's more likely a personality problem, i.e. someone tries to solve a problem using MI it wasn't intended to solve. - Andreas Magnusson
(1) The diamond problem is a well-documented ambiguity that comes up a lot when using multiple inheritance. - Bill the Lizard
And therefore we have virtual inheritance, with all pros and cons. - gimpf
Diamond inheritance causes problems, and combining virtual and non-virtual inheritance can easily cause confusion. Avoid those and you should be all right. - David Thornley
22
[+5] [2008-10-06 16:15:19] finnw

Modify a std::map while you have an active iterator on it. I spent 3 days debugging that once.


(2) only a problem if you delete the item pointed to by that iterator, otherwise you're fine. - gbjbaanb
23
[+5] [2008-10-06 16:26:21] Hans

In a project that does not use namespaces, create a class named Thread with a method called run(). Then make the project use a shared library that, unbeknown to you, also has no namespaces and a class named Thread with a method named run().

No try to figure out that why when you create a thread in your code and pass a pointer to the Thread::run() method as the main body of the thread, your threads never get created.

Good times!


24
[+5] [2008-10-06 16:26:51] Bill the Lizard

Calling a function like this:

int result1 = f( i, i += 2 );

leads to unpredictable results. The function parameter evaluation order isn't specified in the C++ spec, so you don't know if the function will get the current value of i for the first parameter, or if it will be the value of i after i += 2 has been evaluated.


IIRC The coma operator is very well defined. It enforces order from left to right. A better example might be "i + (i+=2)" that might give you some hassles. - Bill K
Yes, but the comma in this example is not a comma operator. - Thomas Padron-McCarthy
It might not be clear from my example, but that's a parameter list to the f() function. - Bill the Lizard
25
[+5] [2008-10-07 01:03:24] shoosh

Circular header dependencies.
If you're not familiar with the pattern of errors that arise from this situation you can go on for hours trying to figure out what the hell is going on.


Before C++, I used Pascal, which makes a clear separation between interface and implementation. And there was a difference between uses in the interface and uses in the implementation. In C++, headers (should) contain the interfaces and .cpp files (should) contain the implementation. (continued) - Eduardo León
26
[+5] [2008-10-07 01:15:59] Causas
#define true false

27
[+4] [2008-10-07 15:54:27] Arkadiy

Different versions of struct in different modules, either because struct is defined in two places, or because the definition has changed and one of the modules was not recompiled (dependencies error). This can cause some fun behavior, such as the value of a field being different inside and outside a function call (we saw it in this [1] question).

[1] http://stackoverflow.com/questions/161490/referenced-structure-not-sticking

Yep. Try passing FILE* structures between a DLL compiled with VC7 and one compiled with VC6. The horror, the horror... - rlerallut
28
[+4] [2008-10-06 22:36:18] KPexEA
the dreaded trailing semicolon after a for loop:

for(i=0;i<1000;++i);
    print("i=%d",i);

output is 'i=1000'

29
[+4] [2008-10-16 22:54:49] Scott Langham

This:

MyObject* DoSomethingNotSoClever()
{
  MyObject object;
  return &object;
}

Doh, object gets destructed and becomes invalid the moment this function returns. If the caller tries to access the returned pointer, they're accessing garbage. It may work for a while until at some time later everything will go bang.


30
[+4] [2008-10-21 06:07:36] Steve Lacey

Operator overloading can be pretty evil. Say you overloaded the operator '*' and you need to modify the implementation/contract. Now, being a good coder, you'll go and check all the uses of the overloaded operator.

Ever tried grep'ing for '*' over a large codebase?


(1) I don't remember if I've ever grepped for 'operator\*'. - Windows programmer
31
[+4] [2008-10-06 16:08:10] workmad3

Relying on default parameters in virtual functions in derived classes.


(1) Good one - you should add an example to illustrate it though. - Richard Corden
32
[+3] [2008-10-06 20:39:07] Milan Babuškov

Forgetting that == has precedence over bitwise operators like & and |. As in:

if (x == y&1)
{

33
[+3] [2008-10-14 22:25:36] SauceMaster
MyObject* A = NULL;
MyObject* B = NULL;
if (A == B == NULL)
{
	//do something
}
else
{
              //do something else
}

You'd wish this if-statement would be the equivalent of saying

 if ((A==NULL) && (B == NULL))

but you'd be wrong.


34
[+3] [2008-10-07 02:41:16] Andrew
delete this;

I can't begin to describe the pain and suffering caused by that one line of code.


I disagree ... "delete this;" is used extensively in COM classes, when a call to Release causes the reference count to reach zero. - Carl
(2) delete this has legitimate uses, I don't see anything particularly painful about it. Can you elaborate? - DrPizza
35
[+3] [2008-10-06 21:44:53] Moishe

Obfuscation. Things like automatic constructors that do too much, overriding operators, throwing exceptions, etc. Even macros to some extent.

C's beauty is that you can look at a snippet of code and have a very good idea of what the assembly does. Java's (or C#'s) beauty is that you don't have to. C++ can be abused to become the worst of these two worlds -- code that needs to be understood at the level of assembly, but is opaque.


36
[+2] [2008-10-07 12:38:25] Dror Helper

Using default values for fuction void Func(int i = 0, bool x = false){...} which is only declared in the header file.

Then trying to track the place where you get false from the 2nd parameter.


37
[+2] [2009-10-03 18:47:52] AareP

Returning pointers to local variables:

const char* getStr(...)
{
  char buf[128];
  return buf;
}

I hate that c++ allows you to do stuff like that without any kind of warning. It is the only thing that needs fixing in c++ - error reporting and warnings.. C++ was apparently programmed by people with mentality "He who make mistakes must suffer"...


If only suffering were a zero-sum game, that would be an excellent paradigm. I know far too many languages where the suffering is inflicted solely on the users. Unfortunately, while C++ makes the programmer experience the users' pain, it doesn't actually reduce the pain felt by the users (unless you count making the pain quicker). - Ben Voigt
38
[+2] [2008-10-06 16:53:05] Kevin Pang

Not understanding pointers is the quickest and easiest way to shoot yourself in the foot using C++.


Can you give a spectacular example? - TonJ
(1) How is this specific to C++ and not C? - Max Howell
39
[+2] [2008-10-06 16:09:07] skaffman

From my C++ days back in the 90s, I was always a fan of

MyType<MyOtherType<T>>

Hello right-shift !


At least you never had to debug that (because it won't compile.) - finnw
A syntax error hardly counts as blowing the whole leg - David Pierre
If I'm not mistaken, C++0x will allow this, and compile correctly. - TonJ
It might not take off your whole leg, but it will result in a slightly embarrassing limp. - skaffman
Whether that compiles at all is actually implementation specific. Most MS VC++ compilers will error on that. - Nick
40
[+2] [2008-10-06 16:51:14] Sam Stokes

If you have a a multithreaded design of any sophistication, and you feel like a few hours tracking down object lifecycle race conditions, try using raw pointers for object ownership.

Smart pointers don't make threads easy, but they certainly help.


41
[+1] [2008-10-06 16:44:38] Scott Langham
int x = 7;
int y = 2;
float result = x / y;

You might think result would be 3.5, but it's 3!


That's really no different than C code. - Andrew
So are a number of the other answers. It's something that's still worth pointing out to somebody trying to get to grips with C or C++. - Scott Langham
42
[+1] [2008-10-06 16:53:17] questzen

The most spectacular way would be to use template driven meta programming. A simpler way would be to override operators and use them without specifying '(' ')'.

On a different note, modifying the header files without changing the .cpp files should also do the trick. Some call this incomplete coding.


43
[+1] [2008-10-06 17:29:42] community_owned

I cut my teeth on assembly, then C, then C++, then C#. I think of C as a clean set of macros for an assembly language. Which I actually like, because I understand every nook and cranny of it. C++ opens up a ton more tricks, but everything in C is still also available. C# finally got wise to this, and even though it still looks very C-like, it blocks some low-level C-type constructs.

One of the thorniest problems I ran into on a huge C++ app turned out to be malloc/free versus new/delete. Anything that's malloced has to be freed, and anything that's newed has to be deleted. But the compiler can't launch flares if something was inadvertently mix-and-matched, so bizarre memory corruption problems can lurk for years. Good luck finding that in your debugging sessions or code reviews.


(1) Well der's your problem. Suggest someone with the rep adding advice here. "huge C++ app" + "malloc/free"? 1) malloc+free should be banished in C++ apps. 2) use smart pointers. - Aaron
(1) 2) Use smart pointers, or make sure to free the memory in the destructor. - TonJ
44
[+1] [2008-10-06 19:50:30] Martin Vilcans

Using raw pointers without documenting ownership. Two typical cases are having a function that returns a pointer without documenting whether the caller takes ownership of it, or having a function that takes a pointer as a parameter without documenting whether it takes ownership of the pointer. (The entity that has "ownership" of a pointer is responsible for deleting it.)

Using smart pointers is a good way to avoid these problems.


I did vote for your answer, but I disagree with your last sentence. Alas, using smart pointers does not mean you never have to worry about ownership again. - TonJ
45
[+1] [2008-10-06 18:21:02] Wedge

Creating a buffer overrun vulnerability.

There are few things worse than opening up a code execution exploit to any user who can input data into your program.


46
[+1] [2008-10-07 12:57:33] plinth
static void MyInterruptServiceHandler(/* ... */)
{
    SomeObject p; // allocates memory in the constructor
    // whoops!  There goes my heap!
}

47
[+1] [2008-10-20 16:49:44] Michael McCarty
while (1) {

// lots of condition tests that don't cover every condition.

}

48
[+1] [2008-10-21 06:05:06] Steve Lacey

Non-const references as arguments are evil as it's non-obvious (from just reading the code at the callsite) that an argument is potentially being modified.

E.g., given:

void do_something(int& foo);

and from reading code at the callsite:

int x = 5;
do_something(x);

it's non-obvious that x could be modified by do_something().


49
[+1] [2008-10-07 08:46:44] David

Unnecessary use of threads.


That probably applies more to other languages, where starting up threads is easier than in C++ (not that it's difficult in C++ mind you). - Ben Voigt
50
[0] [2008-10-07 09:35:14] Dan

Some of the things described in this quiz [1]

[1] http://www.scapecode.com/2008/08/a-simple-c-quiz.html

51
[0] [2008-10-06 16:58:10] Adam Tegen

Overloading * or ->


Can you give an example? A smart pointer must overload * and ->, so that does not count. - TonJ
52
[0] [2009-11-19 11:41:20] Marius

If you go above or below the size of your arrays, then C/C++ will access different things in memory. For example the following code will replace the value of a variable in outside the function.

#include <stdio.h>
#include <stdlib.h>

void f(int x) {
    int a[10];
    printf("a[20] is at address 0x%x\n",(int)&a[20]);

    a[20] = -1; /* change variable answer in main (gcc4.3.2/linux/i86)  */
}

int main(void) {
    int answer = 42;
        printf("answer is at address 0x%x\n",(int)&answer);

    f(5);
    printf("answer=%d\n", answer);
    return 0;
}

Even worse is the following, which will change the place the function returns to, to skip a password checking if statement:

#include <stdio.h>
#include <stdlib.h>

int check_password() {
    char buffer[8];
    printf("Enter password: ");
    gets(buffer);
    int i;
    int * p = (int *) & buffer[20];
        printf("*p is %x\n",*p);
        *p += 4; 
    /* change function's return address on stack (gcc 4.3.2/Linux/i86) */
    return strcmp(buffer, "secret") == 0;
}

int main(int argc, char *argv[]) {
    int k = 7;	
    printf("size of address %d\n",sizeof(int *));
    printf("function main is at address 0x%x\n", &main);
    if (check_password()) {
    	printf("Authenticated\n");
    } else {
    	printf("Password Incorrect\n");
    }
    printf ("bye\n");
}

53
[0] [2009-11-19 17:08:20] David Thornley

Let's see, some interesting things you can do.

Non-explicit type conversions, including constructors. If your class Foo can be converted into a Bar, like Bar::Bar(Foo f), then any function that works on a Bar will work on a Foo, not necessarily correctly. Something like explicit Bar::Bar(Foo f) will work much better.

Overloaded functions that do different conceptual things, depending on the type of the operands. A function Draw(...) that put images on the screen for most things but deployed a gun when used on another thing would be an example.

Similarly, operators that do non-obvious things. operator+() works fine for adding ints and floats and other sorts of numbers or vectors or whatever, or for concatenating strings, but if you use it for anything else, you're setting yourself up for trouble. A related case is turning short-circuit operators into functions, such as operator&&(), which will now evaluate both its operands rather than the first and then possibly the second.


54
[0] [2008-10-06 16:15:50] Scott Langham

You could write a firework launch system in C++ that launches fireworks automatically in time to a piece of loud classical music. Then accidentally stand in front of it with your foot in the way during the finale.

It would be spectacular.

Note (more detail as requested by TonJ): If you work on a system like this, I recommend you avoid try/catch semantics. Using a return for a firework that failed ignition is also a no-no. And, make sure any pointers are initialized to be away from any observers.


shucks. the question mentioned points for originality. don't downvote me :) At least I'd recommend C++ as the best language. If I only had to use one language for everything, C++ would be it. - Scott Langham
(1) I'll upvote you, but please add more detail, like object-oriented rockets with a Rocket Acquisition Is Ignition design pattern, or exothermal template functions. - TonJ
55
[-1] [2008-10-06 16:53:24] Adam Tegen

Not calling delete or delete[]


(1) Couldn't agree less. I use RAII classes or GC for virtually all my memory allocations; if I have to call delete or delete[], it's usually because I'm doing something wrong. - DrPizza
56
[-1] [2008-10-08 03:24:42] Joe Morgan

An infinite loop :P

Also, leaving orphan nodes is a pretty rocking way to hurt yourself.


As far as I can tell, you can have these problem with any languages. - Martin Cote
57
[-57] [2008-10-06 15:58:41] Bill K

By using C++.

Sorry, used it a lot, but this is the worst language ever. If you really really have to be low level, use C. If not, use a real OO language (one with Garbage Collection, C#, Java) or a dynamic language if you are higher level than that.

The only language I can name right now that I would not choose for any purpose is C++


Edit:

Programming in C++ it's virtually impossible to think in OO because you have to track GC. I've virtually never seen good OO c++ code. (It's also somewhat annoying to create new classes because of header files, so most C++ classes seem to be longer and manage more than one concern, another bad OO concept).

I've used C++ and still use it occasionally, but not for OO code, and would never choose it for a new project where the language wasn't set already. I've worked two embedded systems where Java did most of the work including a spectrum analyzer (pretty much an o-scope) where even the trace was drawn in Java.

My point was, C++ doesn't really offer any advantages (It's about twice as fast for the CPU usage, I can't recall the last time I was near 50% cpu usage on one app for more than a second), and has so many ways to shoot yourself in the foot that it's not even funny.

Actually there is another advantage--C++ is the last really hard language and it keeps the barrier to entrance higher. I don't know a lot of C++ programmers who don't understand the language, and many are excellent programmers--so (as opposed to Java, C++, VB and Ruby) C++ apps tend to be a bit more consistently good.


(3) Doooown the toliet you go. - Vicent Marti
(11) Maybe you should suggest that they implement a badge for getting a lot of downvotes. - Kip
(7) @Kip, I agree with you there. It would be something like "Blasphemy" for 20 or more down votes. :) - epochwolf
(2) That browser you posted this from... try writing one of those in C# or Java. - Agnel Kurian
(1) Thanks for stirring up the controversy. I love C++, with all its faults. - TonJ
(1) Anti-C++ respect. Agreement with bill-k here. - ephemient
(5) @epochwolf: "Douchebag" for 50 or more downvotes. :) - Kip
I downvoted this too, not because I disagree one iota, but because it seems to be contrary to the spirit of SO and not an answer to the question... my single downvote decremented it from -14 to -18, so there must be some system in place! - Grank
@Kip, can't argue too much with that. - epochwolf
@Grank, I don't like C++ that much either but this answer is totally out of line in my opinion. - epochwolf
This post is a great way to earn rep, because it will be alternately upvoted/downvoted (you only need 1 in 5 to upvote it and fewer that 5 'offensive' tags.) - finnw
Hasn't worked all that well for Bill K -- at the moment, he's earned 60 points from it, and has had 52 of them taken away by down-votes. :-) - Head Geek
(7) This is the most spectacular way to shoot yourself in the foot with a comment. - Ates Goral
This question doesn't qualify as "helpful." - Robert S.
(1) he got voted down because he made a broad generalized bias comment about C++ as if he spoke for everyone. It did not answer the question but more or else shot down anyone using C++. The tone he uses borderlines "you must be stupid to use C++" - radioactive21
(2) Sorry, didn't mean it as an insult to any person, as I said C++ programmers are usually some of the better ones, and sometimes you don't have an option. That said, I really can't figure out any reason to start a new project in C++ over C and/or Java/C# depending on your task. - Bill K
Being, as I am, a C++ lover (and Java dismisser :P) I just couldn't resist joining the downvoting fest :D This is indeed a great example of how to shoot yourself in the foot!! There needs to be a new badge on SO: "Heretic" or the like, for posting an answer valued less than -10!! - Joe Pineda
(3) @BillK: your comments show you don't really grok C++. Don't need garbage collection if you use RAII. Create new classes because of header files? WTF! Something I hate from Java is its insistence on one class==one file! "Never seen good OO C++ code" and "apps a bit better" - flagrant contradiction? - Joe Pineda
Joe: The fact that C++ code might not be good OO doesn't mean it's not good procedural code and the comment about classes/header files is that I have to edit two files (header and C) to create a class, making class creation more painful. ps in java I can and often do have many classes in one file. - Bill K
(1) The fact that C++ code uses 50% less cycles than Java for the same work may not be so important for your desk PC, it is very important for server farms. If you need 50% less servers to serve the same number of clients, that is a big deal. - TonJ
@TonJ Except for a few very specific cases, most server farms I've seen or heard of are not in C++. Since your example is correct, it seems to be evidence that many companies are willing to pay that price not to have to use C++. Good point, thanks. I wasn't expecting support at this point. - Bill K
A very entertaining conversation. Have you considered this one: C++ could help save the planet because if used correctly it can use less clock cycles than Java etc. This results in less energy burnt and less nasty emissions. - Scott Langham
@Scott I'm kind of wondering how it even went down that road. I never said there was a problem with C, and C is still faster than C++. You can even code C++ as C, that's fine too. but OO without GC is just a silly concept. - Bill K
My opinion is exactly the inverse of Bill K, I wouldn't do anything serious in a another language. If you want to make sure that your app will still compile and work in 10 years, use C++. Very powerful language by the way (if you know how to use it properly). - Martin Cote
ahahaha, -39 neat! well i've got the exact opposite opinion too :) - Johannes Schaub - litb
Yeah, this is one of my favorite posts. It really surprises me how many people defend this language. On the other hand--When I used it it had JUST come out and there was absolutely no memory management, smart pointers or anything that could make it remotely usable. I understand it got a little better, although the boilerplate/syntax ratio (how much boilerplate/non-business related complexity you have to use over the simplicity of the syntax) is still the worst of any language I've seen. - Bill K
@Bill K: I can tell you've never worked in COBOL. - David Thornley
@david thornley Took a class in it. I didn't notice much more boilerplate in COBOL than any of the other biggies of the time, just that the business logic was more verbose, but that was REALLY long ago. This is still my favorite answer discussion by the way. - Bill K
@[Bill K] respect for keeping this answer up, and +1. I doubt even a person with 27 years of C++ experience could convince the downvoters that the language sucks by any modern standard, with the single exception of wide OS support. My theory is that the "converts" are those who actually properly grok a more modern language, rather than "had a quick look and didn't like" it. - romkyns
@Bill K, C++ from the dark ages is not the same as C++ now. - Brendan Long
@Brendan Long I'm using C++ right now. It's worse than I remember. Mostly it's not the language, it's the programmers and the way they choose to use it. I've yet to see a C++ programmer who can think in OO unless he learned it in another language. Some of the flaky hacks that they use to make the code even slightly tolerable are just horrific examples of things you might invent if you wanted to allow a descent programmer to become terrible--macros--OMG. - Bill K
@Bill K, It seems like the people who have a problem with C++ actually have a problem with C (and people who still treat C++ like C). If you treat C++ like a Java with less arbitrary rules (required gc, required classes, etc), it becomes very nice to use. Also, using C++ without boost is just depressing. - Brendan Long
@Brendan Long I actually enjoy C. C++ adds horrible method signatures, breaks classes across files, puts partial implementations into the declaration (header file) and offers you no guaranteed level of support (Can I port to this platform that doesn't support GC--Hmm, complete rewrite today! (I'm working embedded so our code actually has some smart C++ programmer's reference counting implementation--does it work? Yeah! But we're embedded so if you use OO/Ref counting you'll soon trash your heap. All stuff you never have to think about with Java. - Bill K
@Bill K, I don't see how your C++ situation is any worse than using C. No built-in garbage collection, but you still have the massive advantages of: templates, the stl, boost, classes. If any of those features don't work on your platform, then you still have the rest (and at the very worst, you have C with better type checking). And how is Java better? Most likely, it doesn't work on your platform at all, and if it does, it doesn't give you the kind of control over memory that you need in an embedded application. Also, doesn't C use header files as well? - Brendan Long
Actually the code doesn't use any of those--it's cable set-top boxes--small footprint and all. What it does have is cryptic macros hiding implementation and a lot of stuff going on under the covers that I could have identified if it were C. I've come to accept that the best languages are the ones with minimal syntax, remove operator overloading, remove anything that can hide the intent of your code. Not that you HAVE to program poorly if you have those things, just that you WILL HAVE to work on bad code using those things (at least I will, if you don't, you're lucky) - Bill K
@Brendan Long The advantage of C is that nobody WOULD try to write anything large in it any more. It's a great "Portable Assembly Language" which is exactly what it was made for and is still good for quick, hand-coded routines. C++ is a monstrous mess layered on top of that that people feel is appropriate for large code bases not realizing that maintainability is 90% more important than making the code run. You can make something work in any language--but making it maintainable takes effort, and restricting choices helps for the large percentage of programmers that just don't get it. - Bill K
@Bill K Jul 15 '10 at 23:37: C++ is an enormously expressive language that supports several methods or style of programming. If a programmer knows C++ well, then s/he can write well factored and maintainable code in it. If the understanding is shaky the result will be a mess. Personally, I find C# and Java overdetermined and too worried about edge cases - I would not write in them, but I find C++ well determined... but this is a function of my understanding of the three langs, yes? Same for any other tuple of programmer & lang. - Eric M
@Eric M Why do you consider expressive a positive? Remember, programming (for a company, I'm not talking for fun) is most importantly about how hard it is for someone ELSE to comprehend it. The more restrictive the language, the better. It's also critical to be able to write code without redundancy (Most OO languages are pretty good at that). I had a stint in C++ recently and I forgot how horrific the ability to pass void * was--my god. It's not that you HAVE to do that, it's that someone thought it was "Expressive". - Bill K
(1) -1 for saying that people don't write any new large projects in C anymore. - monadic
Downvoting this post is actually a way of upvoting it, because it moves closer to being the most downvoted answer in history! - Mechanical snail
(1) @Mechanical snail true! And still my favorite discussion ever. The reaction to this answer reminds me a lot of how assembly programmers (also known as "Programmers" at the time) increasingly disliked C as the slow, simplistic and restrictive c language slowly pushed their art into the shadows. Oh and since I posted this answer I've used C++ a few more times and the c++ code I've worked on is still miserable OO. (Of course I've never had a problem with using C++ for "C-style" code, I believe I mentioned earlier that I actually like C for fun). - Bill K
58