Pointer

The choice between int* p; and int *p; is not about right and wrong, but about style and emphasis.
  1. C emphasized expressions; declarations were often considered little more than a necessary evil. So typical C programmer writes int *p; and explains it "*p is what is the int". They may point to the C (and C++) declaration grammar to argue for the correctness of the style. Indeed, the * binds to the name p in the grammar.
  2. C++ emphasis on types so typical C++ programmer writes int* p; and explains it "p is a pointer to an int". Indeed the type of p is int*.

The recommended style is the second one, but stick to one pointer per declaration and always initialize variables and the source of confusion disappears.


Don't confuse, these statements are equivalent:
int i;
double d[ARRAYNUM];

int *p1 = &i;
// or
int *p1;
p1 = i;

double *p2 = d;	// or double *p2 = &(d[0]);
// or
double *p2;
p2 = d;

Although ANSI C uses constant 0 as null pointer (#define NULL 0), to ensure portability never assume this. The safety way is assigning pointer to NULL (always do this when declare a pointer but not initialize it yet)
pointertype *pointer = NULL;
and using if (pointer == NULL) or if (pointer != NULL) comparison instead of if (!pointer). NULL is not undefined, as undefined is like this
char *p1 = new char[CHARNUM + 1];
char *p2 = p1;
delete []p1;	// memory is deallocated
cout << p2[0] << endl;	// memory is accessed, but undefined!

This is called dangling pointer, a pointer that points to an object that is already deleted.


Every pointer has an associated type. The difference between pointers of different data types is neither in the representation of the pointer nor in the values (addresses) the pointers may hold—these are generally the same for all data pointers. The difference, rather, is in the type of the object being addressed. The type of a pointer instructs the compiler how to interpret the memory found at a particular address as well as how much memory that interpretation should span. However, function pointers, which address the program text segment, are different from data pointers.

Pointer cannot be initialized or assigned the address value of an object of another type. It is disallowed because although all pointers can hold any memory address value, may interpret the layout and extent of that memory very differently (a function pointer cannot be assigned to it). void pointer can be assigned the address value of any data pointer type to transport that address value or compare it to another address value, but cannot operate on the object pointed by it.


Smart pointers are objects that look and feel like pointers, but are smarter. To look and feel like pointers, smart pointer need to have the same interface that pointers do: they need to support pointer operations like dereferencing (operator*) and indirection (operator->). An object that looks and feels like something else is called a proxy object, or just proxy.

Smart pointer take care of dangling pointers, memory leaks, allocation failures and other memory management. The simplest example is auto_ptr, which is included in the header <memory>. It is a simple wrapper around a regular pointer, the smartness is the destructor takes care of deleting the pointer.
template <typename T>
class auto_ptr
{
  T *ptr;
public:
  explicit auto_ptr(T *p = NULL) : ptr(p) {}
  ~auto_ptr() { delete ptr; }
  T& operator*() { return *ptr; }
  T* operator->() { return ptr; }
  // ...
};

template <typename T>
auto_ptr<T>& auto_ptr<T>::operator=(auto_ptr<T>& rhs)
{
  if (this != &rhs) {
    delete ptr;
    ptr = rhs.ptr;
    rhs.ptr = NULL;
  }
  return *this;
}

// usage in application, need include <memory>
auto_ptr<ClassName> p(new ClassName);
p->DoSomething();
// no need to delete p anymore
Reason to use it:
  1. Less bugs: Automatic cleanup, automatic initialization (no need to initialize the auto_ptr to NULL explicitly), dangling pointer (auto_ptr solves this by setting its pointer to NULL when it is copied).
  2. Other smart pointers may do other things when they are copied. Here are some possible strategies for handling the statement q = p, where p and q are smart pointers. All these techniques help in the battle against dangling pointers. Each has each own benefits and liabilities.
  3. Exception Safety: If DoSomething() throws an exception, all the lines after it will not get executed and p will never get deleted! If lucky this leads only to memory leaks, but if ClassName may free some other resources in its destructor (file handles, threads, transactions, COM references, mutexes) and so not calling it may cause severe resource locks. Using a smart pointer, however, p will be cleaned up whenever it gets out of scope, whether it was during the normal path of execution or during the stack unwinding caused by throwing an exception.

    To write exception safe code with regular pointers

    ClassName *p;
    try {
      p = new ClassName;
      p->DoSomething();
      delete p;
    }
    catch (...) {
      delete p;
      throw;
    }
    

  4. Garbage collection: The simplest garbage collection scheme is reference counting or reference linking.
  5. Efficiency: Smart pointers can be used to make more efficient use of available memory and to shorten allocation and deallocation time. A common strategy for using memory more efficiently is COW. This means that the same object is shared by many COW pointers as long as it is only read and not modified. When some part of the program tries to modify the object ("write"), the COW pointer creates a new copy of the object and modifies this copy instead of the original object. The standard string class is commonly implemented using COW semantics.
    string s1("Hello");
    string s2 = s1; // s2 and s1 point to the same buffer of characters
    s2 += " World!"; // allocate new buffer for s2 before appending, so s1 is unchanged
    

    Optimized allocation schemes are possible when you can make some assumptions about the objects to be allocated or the operating environment. For example, if know that all the objects will have the same size or that they will all live in a single thread. Although it is possible to implement optimized allocation schemes using class-specific new and delete operators, smart pointers give the freedom to choose whether to use the optimized scheme for each object, instead of having the scheme set for all objects of a class. It is therefore possible to match the allocation scheme to different operating environments and applications without modifying the code for the entire class.

auto_ptr is useful as resource handle to minimize the chance of memory leak when need to return an object allocated on the free store from a function.
#includ<memory> // optional for Linux GCC
#include<iostream>
using namespace std;

struct S {
  S() { cout << "make an S\n"; }
  ~S() { cout << "destroy an S\n"; }
  S(const S&) { cout << "copy initialize an S\n"; }
  S& operator=(const S&) { cout << "copy assign an S\n"; }
};

S* f()
{
  return new S; // who is responsible for deleting this S?
};

auto_ptr<S> g()
{
  return auto_ptr<S>(new S); // explicitly transfer responsibility for deleting this S
}

int main()
{
  cout << "start main\n";
  S* p = f();
  cout << "after f() before g()\n";
  // S* q = g(); // this error would be caught by the compiler
  auto_ptr<S> q = g();
  cout << "exit main\n";
  // leaks *p
  // implicitly deletes *q
}
The "move semantics" differs from the usual "copy semantics", so never use auto_ptr as a member of a STL container. The STL containers require the usual copy semantics during assignment. STL containers may copy and delete their elements behind the scenes (for example, when they resize themselves). Therefore, all copies of an element must be equivalent, or the wrong copy may be the one to survive all this copying and deleting. This means that some smart pointers cannot be used within STL containers, specifically the standard auto_ptr and any ownership-transferring pointer.
std::vector<auto_ptr<X> >v; // error
But if the smart pointer assignment is not ownership-transfer, it can be used and release the burden to manually delete the pointers in STL container.
vector<linked_ptr<Base> > v;
v.push_back(new Base);
v.push_back(new Derived);

// cleanup is automatic
auto_ptr holds a pointer to an indiviual element, not a pointer to an array. This is an error because the destructor will delete the pointer using delete rather than delete [] and will fail to invoke the destructor for the last n-1 elements. There is no "auto_array", just use the vector.
auto_ptr<X> p(new X[n]); // error
vector<X> v(n); // ok

Reference counting/linking smart pointer can leak in the case of circular references (i.e., when the pointed object itself contains a counted pointer, which points to an object that contains the original counted pointer). Its advantage over other schemes is that it is both simple to implement and deterministic. The deterministic behavior may be important in some real time systems, where cannot allow the system to suddenly wait while the garbage collector performs its housekeeping duties. They require using locks if the pointers are used by more than one thread of execution.

Suitability of different smart pointers for various situations:
  1. Local variable: auto_ptr
  2. Class member: copied pointer
  3. STL Container: Garbage collected pointer (e.g. reference counting/linking)
  4. Explicit ownership transfer: Owned pointer
  5. Big object: Copy on write
Index