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.
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
- Java has methods
- In Java, everything’s a method, because everything’s in a class.
- C++ has functions & methods
- C++ has methods inside of classes, such as string::length().
- However, C++ also has functions outside of classes, like main().
main
- Java:
public static void main(String[] args)
- C++: int main()
- C++:
int main(int argc, char *argv[])
In C++, main() function returns an int indicating success/failure.
Zero indicates success, positive numbers indicate failure.
It’s not a boolean success indicator. 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:
"a C-style string"
"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
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;
// reed & sue share data
reed[0] = 4;
System.out.println(reed[0] + " " + sue[0]);
4 4
vector<int> ben = {1,2,3}, johnny = ben;
// 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
Faith, the Vampire Slayer
int[] a = {11, 22, 33};
System.out.println(a[-9]);
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -9
at Code.main(Code.java:2)
int a[] = {44, 55, 66};
cout << a[-9] << endl;
cout << a[-90000000] << endl;
-55198512
SIGSEGV: Segmentation fault
- Java throws an exception.
- C++ has faith in you (correctly or not).
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