Show Lecture.Traps as a slide show.
CS253 Traps
C++ traps for the unwary Java programmer
- This is not a list of all Java/C++ differences.
- Instead, it is a list of differences that are likely to cause
problems for a programmer who knows Java but is learning C++.
- Don’t get me wrong—Java is a wonderful language.
- I have no problems with it.
- However, C++ is different in some ways.
- When I point out these differences, there is no implication
of superiority.
- This is not a competition. Please, no wagering.
Prophecy
In 1572, Nostradamus wrote:
When penning in what was twice made more,
In the high city with walls that guard,
Beardless scholars who love beans as black as tar,
Will shine like the Captain of France
This was recently translated as:
When programming in C++,
In Fort Collins, Colorado,
Students who love Java,
Will pull out their hair
Age
If you ask, “Why doesn’t C++ do such-and-such a thing like Java?”,
then you’re asking the wrong question.
I resemble my father—he doesn’t resemble me.
Methods & Functions
- A function is a bunch of code with a name.
- A method is a function that’s part of a class.
- methods ⊂ functions
- A free function is a function that’s not part of a class.
- Java has methods
- In Java, everything’s a method, because everything’s in a class.
- C++ has functions & methods
main
- Java:
public static void main(String[] args)
- C++:
int main()
- C++:
int main(int argc, char *argv[])
In C++, the main() function returns an int indicating success/failure.
Zero means success, positive numbers means failure.
It’s not a boolean value—it’s an integer code.
In C++, main() uses an array of old-style C char * strings,
for compatibility with C.
Poor George Boole
bool b = true;
if (b)
cout << "C++ rules!\n";
C++ rules!
boolean b = true;
if (b)
System.out.println("Java drools!");
Java drools!
Neither is “Boole”, which was the guy’s name.
Booleanosity
In Java, true
is true. In C++, a non-zero value is true.
So is a pointer, unless it’s nullptr.
if (42)
System.out.println("true in Java");
Code.java:1: error: incompatible types: int cannot be converted to boolean
class Code { public static void main(String[] args) { if (42)
^
1 error
if (true && 42 && 3.14159 && 'x' && "hello")
cout << "true in C++\n";
true in C++
Byte
- Java:
char
, byte
- C++: char
- C++: byte (C++17)
C++’s char type is the closest approximation to Java’s byte
.
Java’s char
can hold Unicode characters.
C++’s char has an implementation-defined size, but it’s typically
a single byte, so ASCII only—no ñ, ⻥, or 😈.
final/const/constexpr
In Java, final
indicates a non-overrideable method,
or a constant value.
In C++, final indicates a non-overridable method.
const indicates a method that doesn’t alter object state,
or a value that you can’t change.
constexpr indicates a compile-time constant.
Arrays
- Java:
int[] a = new int[100];
- C++:
int a[100];
In C++, arrays are not objects. Hence, they have no methods.
Hence, you can’t ask an array how long it is. Use a vector
or std::array instead, if you want that.
The simple term “array” is, alas, ambiguous. We will use the
phrases “C-style array” or std::array to resolve this.
Strings
In Java, classes start with a capital letter. That’s not always
so in C++.
"what type am I?"
- Various strings:
cout << "a C-style string";
cout << "a C++ string, alias std::string"s;
char name[] = "C string; no methods";
string s = "C++ string initialized with C string";
- A plain quoted string,
"foo"
, is not an object
of type std::string. It is an anonymous array of constant
characters, or a const char []
, which is pretty much the same
as const char *.
- On the other hand,
"bar"s
(with a trailing s
)
is a C++ string object.
- You can assign a C string to a C++ string,
or use a C string to initialize a C++ string.
Objects: heap or not?
- Java:
String s = new String;
- C++:
string s;
- In Java, objects are always in the heap (dynamic memory),
and scalars (int, double) are always on the stack.
- In C++, both objects & scalars can be on the heap or the stack,
as you choose. The stack generally makes for easier code—don’t have
to invoke new and delete.
- Java programmers have a lot of trouble with this, so this course
generally forbids using new in homework. Get used to it!
String Subscripting
String s = "abcdefg";
System.out.println(s.charAt(3));
d
string s = "hijklmn";
cout << s[3] << '\n';
cout << s.at(4) << '\n';
k
l
- Sure, C++ has the string::at() method, but, why?
- Error checking, that’s why.
Order of Operations
Java yields 5
, because the order of operations is defined: left side
++
, then right side --
, then +
.
int n=2;
System.out.print(++n + --n);
5
C++ invokes undefined behavior. The compiler is free to do the
operations (++
, +
, --
) in whatever order it likes. The
compiler is not required to tell you that you broke the rules,
though a good compiler might, if you ask nicely (-Wall
):
int n=2;
cout << ++n + --n; // 🦡
c.cc:2: warning: operation on ‘n’ may be undefined
c.cc:2: warning: operation on ‘n’ may be undefined
4
Plus-sign overloading
System.out.println("foobar"+3);
foobar3
cout << "foobar"+3 << '\n';
bar
In Java, +
is overloaded to handle arguments of String
and
int
, and so yields "foobar3"
.
C++ performs address arithmetic in this case, and so yields "bar"
.
Pointers and references
- Java has only references, which are like pointers with automatic
indirection.
- C++ has both explicit pointers, and references.
int[] reed = {1,2,3}, sue = reed;
// In Java, reed & sue share data.
reed[0] = 4;
System.out.println(reed[0] + " " + sue[0]);
4 4
vector<int> ben = {1,2,3}, johnny = ben;
// In C++, johnny is a copy of ben.
ben[0] = 4;
cout << ben[0] << ' ' << johnny[0] << '\n';
4 1
This C++ code uses no pointers or references.
Copying
- Java:
obj1 = obj2;
- C++:
obj1 = obj2;
In Java, this copies a reference. No new object is created, no real
data is copied. This is a shallow copy. If I modify obj2
, it
changes obj1
, because there’s only one object, with two references
to it.
In C++, the copy ctor of the class is called. This typically copies the
data in the object, making this a deep copy. If I modify obj2
,
obj1
doesn’t change—they’re separate objects.
Method/Member Access
String s = "foobar";
System.out.println(s.length());
6
string a = "xyzzy";
string *b = new string("alakazam");
cout << a.length() << ' ' << b->length() << '\n';
cout << a.size() << ' ' << b->size() << '\n';
5 8
5 8
- Java:
alpha.beta()
, since alpha
can only be a reference.
- C++:
alpha.beta()
or alpha->beta()
,
because alpha
might be an object, a reference to an object,
or a pointer to an object.
Garbage Collection
- Java: garbage collection
- C++: delete and
delete[]
In C++, your options are (hardest to easiest):
- Allocate memory with new /
new[]
,
deallocate with delete / delete[]
.
- Use container classes like vector or set which do the
memory allocation/deallocation for you.
- Just use the stack.
Out of Bounds
- C++ has faith in you (justified or not).
- Java throws an exception.
int a[] = {44, 55, 66};
cout << a[-9] << endl; // 🦡
cout << a[-90000000] << endl; // 🦡
2142055632
SIGSEGV: Segmentation fault
int[] a = {11, 22, 33};
System.out.println(a[-9]); // 🦡
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -9
at Code.main(Code.java:2)
Nothingness
In Java, null
is the reference to nothing.
In C++, a pointer to nothing useful can be initialized
to nullptr or NULL or 0
.
- nullptr is best.
- NULL is compatible with C.
0
is just plain silly.
Really, just pointers
⁰/₁
- Java programmers, used to references, tend to think that NULL
is magic, and that anything can be null. They often guess that
uninitialized variabes are null, whatever that means.
- Only pointers can be nullptr or NULL. Not objects, not
numbers, not C++ string objects.
- A 32-bit integer cannot be nullptr or NULL.
- It’s 32 bits. Each bit is either a zero or a one. A bit can’t
be anything but zero or one. A bit can’t possibly be
null–what would that mean‽ Put those 32 bits together, and you get
a number. Nothing else is possible.
Parting Shot