9/25/2015
Pointers are fundamentally simple. They simply tell you where a value is rather than giving you the actual value. However, because of how destructors work, they can be dangerous to use in certain situations. Let's look at an example of a pointer:
#include <iostream> int main() { int* int_ptr = new int(0); std::cout << *int_ptr << std::endl; // memory leak! This is not caught by compiler! int_ptr // is never deleted add ``delete int_ptr`` to the end, or // use a value type int instead }
This shows the basic usage of a pointer. In Java, ints are always value types, so you have to return an int to modify a variable. In C++, everything is a value type unless explicitly marked as a pointer or reference.
Pointers are different from references in that their
semantics require a dereference before usage. You can
dereference a pointer into a value bye using the
unary *
operator. However,
the *
operator is annoying as it is right
associative. This means that *ptr.y = 10;
would be invalid as the ptr isn't dereferenced before
usage! To overcome this, use the ->
operator, which basically replaces ptr->y
with (*ptr).y
. In C++ the this
keyword is just a pointer to self, meaning that you have
to use this->field
to access something
rather than this.field
. Note that
Java's .
operator is literally the exact same
as C++'s ->
operator.
Pointers allow you to access native memory locations, so a pointer and int pair is all that an array really is! Let's implement a simple class to represent an array:
#include <stdexcept> // std::out_of_range // forces generic usage of this like Array<int> for // types, Array by itself is compile error! template<class T> class Array { private: T* array_start; unsigned int length; public: // constructor Array() { array_start = new T[10]; length = 10; } // destructor ~Array() { // not null test if(array_start) delete[] array_start; // non pointers auto destructed } // random access - could commit suicide T& operator[](int index) { return array_start[index]; } // checked access - throws exception if out of bounds T& at(int index) { if(index < 0 || index >= length) throw std::out_of_range("Index out of range"); return array_start[index]; } }; // all structures must end with semicolon
A potential problem is that any copies of
this Array
don't make a deep copy, they just
copy the pointer location, resulting in a possible double
deletion! It also just isn't good style to have
constructors written this way, because if any of the
values were const
, then it would be a syntax
error! Let's fix the constructors:
Array() : array_start(new T[10]) , length(10) { }
This now constructs the values with new T[10]
and 10
rather than copying them in after they
have been constructed. It also separates the
initialization from the code and makes it cleaner overall.
Now let's get into the real problem with the class, any
copies are not true copies! C++ has an implicitly defined
method called a copy constructor on every object. It is
called to initialize a copy of an object. For this
reason, there is no generic clone method, just
use <type> copy = old;
! The auto
generated copy constructor works great for classes without
pointers but not so well when there are pointers. Every
copy constructor should be accompanied by a copy
assignment operator, as show below. The copy constructor
and copy assignment operators need to take a const
reference to the type, such as const
Array&
.
#include <algorithm> // std::copy // copy constructor Array(const Array& other) : array_start(new T[other.length]) , length(other.length) { std::copy(other.array_start, other.array_start + length, array_start); } // copy assignment operator Array& operator=(const Array& other) { length = other.length; if(array_start) delete[] array_start; array_start = new T[length]; std::copy(other.array_start, other.array_start + length, array_start); // remember to always ``return *this;`` so it can be // assigned to in function arguments. return *this; }
As you can see, pointers and pointer arithmetic are really cool and powerful but they make it easy to "shoot yourself in the foot" if you don't know what to do with them.