Posts tagged ‘cpp is bad’

C++ is bad: structs aren’t the same as structs

Here’s a fun little problem. Suppose you’ve got a system that makes use of the following struct:

struct User {
  unsigned int user_id;
  unsigned short access_level;
  float account_balance;  // stored as US dollars
}

Your system is ridiculously well-tested, all the tests pass, everything works totally fine. I’ll be so bold as to say it’s (kinda) bug-free.

One day, you decide to add a new field to the User struct, a string called name. You recompile everything, and suddenly all kinds of tests fail! New users have all kinds of access levels, some have account balances in the billions while others have accounts worth negative billions. What happened, why, and how do you fix it (without removing name again)? Edit: and no, the code does not rely on brittle assumptions about the value of sizeof(User), nor does it break type safety and have unsafe casts or void*’s pointing into the middle of Users. That would be too easy.

The answers, and more →

C++ is bad: inheritance is counterintuitive

In our latest installment of “why not to program in C++,” let’s take a look at a simple class hierarchy:

class Duck {
 public:
  Duck() {
    InitializeMigratoryRoute();
  }

  // Default behavior is nonmigratory; this is
  // overridden in the Mallard class.
  virtual void InitializeMigratoryRoute();
}

class Mallard : public Duck {
 public:
  Mallard();

  // Migrate south in the fall and north in the spring
  virtual void InitializeMigratoryRoute();
}

class DonaldDuck : public Duck {
 public:
  DonaldDuck() {
    outfit_.AddShirt(Outfit::Shirts::SAILOR);
    outfit_.AddHat(Outfit::Hats::SAILOR);
  }

 private:
  Outfit outfit_;
}

You can assume this code compiles and runs (i.e., the Outfit class is defined, it implements AddShirt(), both versions of InitializeMigratoryRoute() are defined, etc). I would say this looks like perfectly reasonable code: its intention is clear and straightforward, and any sane language should have no trouble implementing this. [1] However, we’re dealing with C++, which means there are always more problems, and in fact this code is not in the least alright. In particular, there are two major things wrong with it. Do you see what they are?

This code has two major problems. →

C++ is bad: problems with the ternary operator, addendum

I’ve found another interesting wrinkle in the ternary operator. So, here’s a bonus question for that quiz from last time. You start with the following code:

class Abstract;
class DerivedOne;  // Inherits from Abstract
class DerivedTwo;  // Inherits from Abstract
Abstract x;
DerivedOne one;
DerivedTwo two;
bool test;

Again, you can assume that all of these are defined/initialized (and you can assume the comments are correct—both Derived* classes inherit from Abstract). Now, consider these snippets:

# Code Snippet
A
Code Snippet
B
Bonus
if (test) x = one;
else x = two;
x = (test ? one : two);
 


If you read the previous installment, you’ve probably guessed by now that these are not equivalent, and you’d be right. In what ways do they differ?

Another unexpected answer →

C++ is bad: problems with the ternary operator

In today’s installment of “why not to program in C++,” I give you the following quiz, which Dustin, Steve, Tom, and I had to figure out today (Dustin’s code was doing the weirdest things, and we eventually traced it down to this):

Suppose you start out with the following code:

class Argument;
Argument x;
void Foo(const Argument& arg);
bool test;

You can assume that all of these are defined/initialized elsewhere in the code. For each pair of code snippets below, decide whether the two snippets are equivalent to each other.

# Code Snippet
A
Code Snippet
B
1
if (test) Foo(x);
else Foo(Argument());
Foo(test ? x : Argument());
 
2
{ // limit the scope of y
  Argument y;
  Foo(test ? x : y);
}
Foo(test ? x : Argument());
 
 
 
3
Foo(x);
Foo(test ? x : x);
4
Foo(x);
Foo(true ? x : Argument());


Edit: what I meant by the curly braces in Question 2 is that you shouldn’t consider “y is now a defined variable” to be a significant difference between the two snippets.

The answers are worse than you'd think. →