CS62 - Spring 2011 - Lecture 30

  • What would the following print out in Java?
       - Case 1:
          int x = 10;
          int y = x;
          y = y + 10;
          System.out.println(x)

       - Case 2:
          ArrayList<Integer> x = new ArrayList<Integer>();
          ArrayList<Integer> y = x;
          y = null;
          System.out.println(x)

       - Case 3:
          ArrayList<Integer> x = new ArrayList<Integer>();
          ArrayList<Integer> y = x;
          y.add(10);
          System.out.println(x);
          
       - Why do these behave differently?

  • memory in Java
       - stack (run-time stack)
          - ALL variables go on the stack
          - eight built-in types
             - whenever you create these, they reside directly on the stack
             - the built-in types are NOT references
             - the = operator copies the value
             - in Case 1 above, y gets copy of x, but they are distinct variables
          - everything else is a reference to an object
             - a reference is another variable, and it too goes on the stack
             - similar to above, the assignment operator simply copies the value of x to y, e.g. a reference to an ArrayList
             - we can change the value of y and it won't affect x
             - in Case 2 above, changing the value of y, does not change what is referenced by y (or x)
       - heap
          - anytime you say new, you get a new object on the heap, and you end up with a reference
          - in Case 3 above, x and y reference the same object and the add method changes the object referenced by y (and x)

  • look at first.cpp code
       - what does max do?
          - finds the maximum value in the vector
          - looks almost identical to what we would write in Java
             - rather than using get and set, we access elements via [], like in an array
       - what does simpleVersion() do?
          - creates a new vector
             - how many elements in it initially?
                - 0, it uses the default constructor
          - adds 1, 2 and 3 to the vector
          - calls max, to get the maximum value
          - prints out the maximum value to the console
             - in this case, 3
       - what does moreInteresting() do?
          - again, creates a new vector
          - creates a second vector nums2
          - sets the first entry in nums to be 15 (rather than 1)
          - calls max on nums2
          - what do you think is output?
             - two options:
                - 3
                - 15
          - what would be output in Java?
             - 15
          - 3 is actually output
          - what does this mean? why do you think this happens?
             - nums and nums2 are different objects

          
  • memory in C++
       - has both a heap and a run-time stack
       - like Java, any variable you construct without using the keywords "new" is created on the run-time stack
       - also like Java, a variable that isn't assigned to something on the heap is NOT a reference
       - where is "vector<int> nums" created?
          - it's a vector that is created on the run-time stack!
       - this still doesn't fully explain our example?
          - we know that "vector<int> nums2" is not a reference
             - it doesn't reference anything on the heap
             - there's a special notation for references in C++
          - copy constructor
             - all objects have a copy constructor (either explicitly defined or implicitly)
             - the copy constructor takes an object of that type and creates a new copy
          - nums2 ends up as a new vector on the stack that is a copy of nums
          - therefore, changes to nums, do not affect nums2 and vice versa

  • the C++ compiler
       - in first.cpp code, what is:

       void simpleVersion();

       - the C++ compiler starts at the top of the file and works its way down
       - it only knows about the methods that it's seen so far
       - therefore, if you want to use a method that you define later on, you need to include the method header declaration before using it

  • writing a class
       - look at intcell_basic.cpp class in intcell.cpp code
       - what does this class do?
          - a shell class to hold an int
          - similar to the Integer class in Java
       - what are some of the differences you notice between Java and C++?
          - there is a "public" section and a "private" section where public and private things are defined
             - you don't use the keywords public/private individually on a method
          - semi-colon at the end of the class definition, it's just a statement
          - you can put multiple class definitions in a file

  • header files
       - As we noted above, you need to declare methods before you use them
       - when declaring a class, the common thing to do in C++ is to split the class definition into two parts:
          - a "header" file (with a ".h") extension with the definition of the class, the methods headers and the variables
          - an "implementation" file (with a ".cpp") that has the actual definition of the methods
       - look at intcell_take1.h in intcell.cpp code
          - the header file looks just like our class definition, except none of the methods have bodies
       - look at intcell.cpp in intcell.cpp code
          - first line includes the header file
             - what does this do?
                - remember a #include simply copies the contents of the file
                - now we know we have those methods available
          - notice that it is only method definitions and nothing else in the file. All of the variable declarations, etc. are in the header file
       - what does "IntCell::" mean in front of all the methods and why is it there?
          - defining a class, defines a new namespace
          - to differentiate between a global method getValue() and the one for the class IntCell, we need to use "IntCel::"
       - notice that we don't have any public/private annotation on the methods in the .cpp file, only in the header file
       - this is the approach we're going to use for this class
       - what benefit does this have?
          - what we've talked about a lot in the class is a separation of definition and implementation
          - makes the code clean, by avoiding having to put in method header declarations in the code
          - faster to compile! why?
             - what does #include do?
                - copies the file
             - every time we recompile, we'll have to recompile all of the code we imported
          - allows us to share compiled code, without sharing the actual code (more on this later)
       - compiling with header files
          - you don't need to explicitly compile header files. Why?
             - they're included with #include

  • const
       - what are accessor and mutator methods?
          - an accessor method does not modify the class data
          - a mutator method changes the data
       - in C++, the keyword "const" after a method declaration states that that method is an accessor method
          - it's a contract between the programmer and the compiler that we won't be modifying the object
       - what methods could be const in IntCell?
          - getValue
          - make the change and recompile
             - notice that you need to change it in both the header and the cpp file. It is part of the method declaration
       - if we try and add const to setValue(), we get a compiler error:
          "intcell.cpp: In member function Ôvoid IntCell::setValue(int) constÕ:
          intcell.cpp:12: error: assignment of data-member ÔIntCell::valueÕ in read-only structure"
       - again, we will do this in the class
       - what benefit does this have?
          - another way of communicating with other programmers and the compiler
          - forces you to think about your code :)
          - allows the compiler to make optimizations and makes your code faster

  • #ifndef, #endif and #define
       - what happens if we try to declare a method twice (or just the method header twice)?
          "intcell.h:4: error: ÔIntCell::IntCell(int)Õ and ÔIntCell::IntCell(int)Õ cannot be overloaded"
          
          - compiler thinks that you're trying to "overload" a method
             - what is an overloaded method?
          - can't declare the same method twice
       - what if we said:
          #include "intcell.h"
          #include "intcell.h"

          in a file?
          - we'd get similar errors for all of the methods
       - the example above is contrived, but this can happen easily, when?
          b.h:
             #include "a.h"
          c.h:
             #include "a.h"
             #include "b.h"
       - to avoid this, you'd like to be able to state that you only want the header file to be copied once for any compilation
       - we do this with preprocessing statements
       - look at intcell.h in intcell.cpp code
          - #ifndef
             - "if not defined"
          - #define
             - define the variable
          - #endif
             - end the if statement (don't forget this)

  • admin
       - CS senior presentations Thursday and Friday afternoon
       - guest lecturer on Friday in class
       - send videos

  • assignment 10 things
       - commenting
       - pair and map classes (read the specifications!)
          - pair
             - used to store two items (a first and a second)
          - map
             map<int, int> m; // sets up a new map (hashtable) with an int key and an int value
             m[0] = 4; // sets key 0 to have value 4
             m[17] = 7; // sets key 17 to have value 7

             - to ask if something exists, use the count method (do NOT try and use [] to see if something exists)
       - destructors
          - in C++ we have constructors AND destructors
          - a destructor is called when an object is getting deleted/removed and is a chance for an object to clean up anything it needs to
          - like the constructor, the destructor has the same name as the class, but is preceded by a '~', for example:
             ~IntCell();

             would be the define the destructor for the IntCell class and then we could define it in the .cpp file as:

             IntCell::~IntCell(){
             }
          - for this assignment, we'll include the destructor just to get you in the habit of it, however, you won't need to put any code in it
       - debugging when compiling at the command-line
          - if you get compiler errors, go to the top (i.e. the first error) and fix that one then recompile
          - "segmentation fault"
             - this is C++'s nice way of telling you you screwed up
             - equivalent to a run-time error
          - use print statements (i.e. cout or cerr)

  • differences between ArrayList and vector classes
       - what would the following print out?
          vector<int> nums(10);
          nums.push_back(1)

          for( int i = 0; i < nums.size(); i++ ){
             cout << nums[i] << endl;
          }
       
       - be careful about making assumptions about the behavior of classes
       - the one parameter constructor for vector in C++ creates a vector which contains 10 elements in it already
          - after calling the constructor, those elements exist and we can access the elements

          vector<int> nums(10);
          nums[8] = 10;

       - what would happen if we did this in Java?
          - index out of bounds exception
       - what do you think will happen if we do:

          vector<int> nums;
          nums[8] = 10;

          - run-time error (aka segmentation fault), just like Java, we cannot access elements in the vector that have not been instantiated (either via a push_back or via the constructor)