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
}
|
Go4Expert Member
|
|
| 7May2006,11:34 | #21 |
|
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
}
|
|
Go4Expert Member
|
|
| 7May2006,11:36 | #22 |
|
Can you tell what the following declaration means?
Code:
void (*p[10]) (void (*)() ); Code:
typedef void (*pfv)(); Code:
typedef void (*pf_taking_pfv) (pfv); Code:
pf_taking_pfv p[10]; |
|
Go4Expert Member
|
|
| 7May2006,11:37 | #23 |
|
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
};
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. |
|
Go4Expert Member
|
|
| 7May2006,11:38 | #24 |
|
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; Code:
void (vector< string >::*v_vs_szt) (size_t) = &vector< string >::reserve; // string specialization |
|
Go4Expert Member
|
|
| 7May2006,11:40 | #25 |
|
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
}
|
|
Go4Expert Member
|
|
| 7May2006,11:41 | #26 |
|
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
}
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
}
|
|
Go4Expert Member
|
|
| 7May2006,11:46 | #27 |
|
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
|
|
Go4Expert Member
|
|
| 7May2006,11:48 | #28 |
|
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
}
|
|
Go4Expert Member
|
|
| 7May2006,11:49 | #29 |
|
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 |
|
Go4Expert Member
|
|
| 7May2006,11:51 | #30 |
|
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(); Code:
int func(int * p);
int main()
{
func(iter); // error, iter is not a pointer to int
}
Code:
int main()
{
func( &*iter); // ok
}
|