0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
You can declare a reference to a function, just like you can declare a pointer to a function. For example:


Code:
void f(int n)
{
  ++n;
}

int main()
{
  void (&rf) (int) = f; //bind rf as a reference to f()
  rf(5); //call f() through its reference
}
The major difference between a pointer and a reference to a function is that the latter must always be bound to an existing function (i.e., it may not be null or dangling), and you cannot re-bind another function to it once you have initialized it.
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
Can you tell what the following declaration means?


Code:
 void (*p[10]) (void (*)() );
Only few programmers can tell that p is an "array of 10 pointers to a function returning void and taking a pointer to another function that returns void and takes no arguments." The cumbersome syntax is nearly indecipherable. However, you can simplify it considerably by using typedef declarations. First, declare a typedef for "pointer to a function returning void and taking no arguments" as follows:


Code:
 typedef void (*pfv)();
Next, declare another typedef for "pointer to a function returning void and taking a pfv" based on the typedef we previously declared:


Code:
 typedef void (*pf_taking_pfv) (pfv);
Now that we have created the pf_taking_pfv typedef as a synonym for the unwieldy "pointer to a function returning void and taking a pfv", declaring an array of 10 such pointers is a breeze:


Code:
pf_taking_pfv p[10];
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
Sometimes it is tempting to let a pointer point to a location that is slightly beyond an array's index range. For example, consider the following self-defined array class, which allows you to define arrays whose index ranges do not necessarily start at zero:


Code:
    template 
     class MyArray
       {
         T*  ptr;
         int f, l;
       public:
         MyArray (int first, int last)
           : f(first), l(last)
           {
             ptr = new T [last-first+1];  // Why +1?
             ptr -= first;
           }
         T& operator[] (int index)
           {
             return ptr[index];
           }
         // Further methods
       };
The trick is simple and elegant and might result in very efficient code: Since the address stored in ptr differs from the address of the real array by the value of first, first need not be subtracted from index in operator[]. A neat trick, right?

Unfortunately, the C++ standard draft says that a call to operator[] would result in undefined behavior. Even if it runs fine on your system, there are definitely systems on which this is not the case. An expression with pointer arithmetics is well defined only if all involved pointers and all results of partial expressions point to elements of one--and only one--array.
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
You can define a pointer to a class template member. For example, you can use the specialization vector<int>:

Code:
 	
typedef void (vector< int >::*v_vi_szt) (size_t); // v_vi_szt is used to hide the unwieldy syntax
v_vi_szt  reserve_ptr = &vector< int >::reserve;
The only difference from ordinary pointers to class members is that you are required to use a template specialization, since a template name per se is not a type. In other words, you have to define a separate pointer to member for every specialization used. In the following example, vector <string> specialization is used (no typedef applied in this case):

Code:
void (vector< string >::*v_vs_szt) (size_t)  = &vector< string >::reserve; // string  specialization
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
C and C++ define a special type for pointer arithmetic, namely ptrdiff_t, which is a typedef of a platform-specific signed integral type. You can use a variable of type ptrdiff_t to store the result of subtracting and adding pointers. For example:

Code:
#include <stdlib.h>
int main()
{
  int buff[4];
  ptrdiff_t diff = (&buff[3]) - buff; // diff = 3
  diff = buff -(&buff[3]); //  -3
}
What are the advantages of using ptrdiff_t? First, the name ptrdiff_t is self-documenting and helps the reader understand that the variable is used in pointer arithmetic exclusively. Secondly, ptrdiff_t is portable: its underlying type may vary across platforms, but you don't need to make changes in the code when porting it.
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
Even experienced C++ programmers who have prior experience with C tend to use pointers excessively whereas references may be a better choice. Pointers may result in bugs like the following:


Code:
bool isValid( const Date *pDate);

void f()
{
	Date *p = new Date(); //default: current date

	//...many lines of code

	delete p;		//p is now a “dangling pointer” 
	bool valid = isValid(p); //oops! undefined behavior
	p = NULL;
	valid = isValid(p)	//ops! null pointer dereferencing; 	
					//most likely will lead to a crash
}
The use of references eliminates the notorious bugs related to pointers: null pointer assignment and dangling pointer dereferencing, since a reference is always bound to a valid object:

Code:
bool isValid( const Date& date);  //reference version

void f()
{
	Date date; //default: current date

	//...many lines of code

	bool valid = isValid(date); //always safe
	date += 100; //add 100 days
	valid = isValid(date)	//always safe					
}
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
Whenever your class contains pointers, references, or handles, you need to define a copy constructor and assignment operator. Otherwise, the compiler-generated copy constructor and assignment operator will result in aliasing, that is to say, the same resource will be used simultaneously by more than one object and will also be released more than once - with disastrous results:

Code:
class Document {
private:
	FILE *pdb;
public:
	Document(FILE *f =NULL) : pdb(f){}  //no user-defined copy constructor or operator=
	~Document() {fclose(pdb);}
	//...
};
void assign(Documnet d&)
{
Document temp("letter.doc");
d = temp;  //Aliasing; both d and temp now point to the same file
}//temp's destructor is now automatically called and closes file letter.doc while d is still using it  
void main() 
{
Document doc;
assign(doc);
//OOPS! doc now uses a file which has just been closed 
}//OOPS! doc's destructor is now invoked and closes 'letter.doc' once again
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
The Standard Library supplies the class template auto_ptr<> which automatically deallocates heap memory. Likewise, local objects are reclaimed in case of exiting their scope or during "stack unwinding" caused by an exception.

This technique can avoid memory leakage in the case of uncaught exception or even simplify programming by sparing the hassle of explicitly deleting every object allocated using operator new. The auto_ptr<> class template is declared in the standard <memory> header.
Code:
 
#include <memory> //auto_ptr<> declaration
#include <iostream>

using namespace std;

class Date{ /*...*/};

void DisplayDate()
{
	//now create a local object of type auto_ptr<Date> 
auto_ptr<Date> pd (new Date); //now pd is owned by the template object
	cout<<pd->DateString();

//note: pd is automatically deleted by the destructor of auto_ptr; it shouldn't be deleted by programmer

}
In other words, the auto_ptr<> instance, pd, can be used like an ordinary pointer to Date but it behaves like a local object in respect to its automatic destruction.
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
Most C++ users already know that they shouldn't use auto_ptr objects as elements of STL containers. However, fewer users know exactly why this is so.

The C++ Standard says that an STL element must be "copy-constructible" and "assignable." These fancy words simply mean you can safely assign or copy one object to another and get two independent and logically identical copies. In particular, the state of the original object shouldn't change when it is copied to the target object.

This is not the case with auto_ptr, though: copying or assigning one auto_ptr to another makes changes to the original, in addition to the obvious changes to the copy. To be more specific, the original object transfers ownership of the pointer to the target, and the pointer in the original object becomes null. Imagine what would happen if you did something like this:


Code:
 class Foo{};
  vector  < auto_ptr <Foo> > vf; //a vector of auto_ptr's
  //..fill vf
  int g()
  {
    auto_ptr <Foo> temp = vf[0]; // vf[0] becomes null
  }

When temp is initialized, the member vf[0] is changed: its pointer becomes null. Any attempt to use that element will cause a runtime crash. This situation is likely to occur whenever you copy an element from the container. Remember that even if your code does not perform any explicit copy or assignment operations, many algorithms (swap(), random_shuffle(), sort(), and many others) create a temporary copy of one or more container elements. Furthermore, certain member functions of the container may create a temporary copy of one or more elements, thereby nullifying them. Any subsequent attempt to the container elements is therefore undefined.

Several Visual C++ users report that they have never encountered any problems with using auto_ptr in STL containers. This is because the auto_ptr implementation of Visual C++ (all versions thereof) is outdated and relies on an obsolete specification. When Microsoft decides to catch up with the current ANSI/ISO C++ Standard and change their Standard Library accordingly, code that uses auto_ptr in STL containers will manifest serious malfunctions.

To conclude, you shouldn't use auto_ptr in STL containers. Either use bare pointers or use other smart pointer classes instead of auto_ptr
0
subhasish's Avatar, Join Date: Mar 2006
Go4Expert Member
Suppose you define a the following list object and you need the address of one of its elements:


Code:
 std::list <int>  li;  
  std::list <int>::iterator  iter = li.begin();
In many contexts, iter functions like a pointer. However, when you need a real pointer to a container's element, you can't use an iterator:

Code:
  int func(int * p);  
  int main()
  {
    func(iter); // error, iter is not a pointer to int
  }
The problem is that in general, iterators aren't pointers. Rather, they are usually implemented as objects. To get a pointer to the element an iterator refers to, you need to "dereference" that iterator and take the address of the result. For example:

Code:
  int main()
  {
    func( &*iter); // ok
  }