C++ Common Knowledge by Stephen C. Dewherst

I want to share some information from the book of Stephen C. Dewherst about his book.. He discusses C++ Common Knowledge.
Enjoy!

Item 1 – Data Abstraction
Type – a set of operations
Abstract Data Type – set of operations with an implementation
* What can I do with this object, not how is this object implemented.
The purpose of ADT is to extend the Programming language into a particular problem domain
ADT will change much more frequently than their interfaces.

Approaches in designing ADT
1. Choose a descriptive name for the type.
2. List the operations that the type can perform.
3. Design an interface for the type. (easy to use and hard to use incorrectly)
4. Implement the type.

Item 2 – Polymorphism
According to standard,
– “a polymorphic type” is a class type that has virtual function.
– “a polymorphic object” is an object with more than one type
– “a polymorphic base class” is a base class that is designed for use by P.O.

---------------
| Option |
---------------
| price() |
| update() |
----------------
/ \
/ \
------------- -----------------
| AmOption | | EuroOption |
------------- ------------------

AmOption *d = new AmOption;
Option *b = d;
d->price(); // if this calls AmOption::price..
b->price(); // so should this

Item 3 – Design Patterns
- are an essential component of the professional C++ programmer’s toolkit.
- recurring architectural pattern
- programmer to programmer communication
- patterns wonks sometimes describes DP as a form of literature that follows a certain formal structure.
- often described as “micro architectures”

Design Pattern’s Formal Structure
1) Patterns must have an unambiguous name.
2) Pattern descriptions must define the problem addressed by the pattern.
3) The PD describes the problem’s solution.
4) The PD describes the consequences of applying the pattern to the context.

Item 4 – The Standard Template Library
- the STL isn’t a library. It’s an inspired idea and a set of conventions.
- an STL algorithm is an abstraction of a function, implemented as a function template
- an STL container is an abstraction of a data structure, implemented as a class template
- an iterator is like a pointer, the first iterator refers to the first element of the sequence while the second iterator refers to one past the last element of the sequence, (not the last element). if both iterators refer to the same element, they define an empty sequence.
- clearer and more maintainable code
- Learn the STL and use it extensively

3 Major Kinds of Components
1) Containers – contain and organize elements
2) Algorithms – performs operations
3) Iterators – for accesing elements

Item 5 – References Are Aliases, Not Pointers
- A reference is another name for an existing object
- references are often confused to pointers

int a = 12;
int &ra = a; // ra is another name for a
--ra; // a == 11
a = 10; // ra == 10
int *ip = &ra; // ip points to a

3 Major Differences between References and Pointers
1) There are no null reference,
2) all references require initialization
3) A reference always refer to the object with which it is initialized.

Item 6 – Array Formal Arguments
- problematic because there are no array formal arguments because array is passed as a pointer to its first element
- decay, an array decays to a pointer of its first element

void average( int ary[12] ); // formal arg is int*

int anArray[] = {1, 2, 3 }; // three element array
const in anArraySize = sizeof(anArrary)/sizeof(anArray[0]); // == 3
average(anArray); // legal

void average(int ary[]); // formal arg is still int*
void average(int (&ary)[12]); // precise value
- will only accept an array with size 12
//…
- templates help to generalize somewhat

template
void average(int (&ary)[n]); // let compiler deduce n for us

- traditional
void average_n(int ary[], int size);

- or can be combined
template
inline void average(int (&ary)[n])
{ average_n(ary,n);}

int *anArray2 = new int[anArraySize];
average(anArray2); // error! can’t init int(&)[n] with int*
average_n( anArray, anArraySize ); // OK…

- multidimensioal array formal arguments are not essentially different but more challenging.

Single – Pointer to the array’s first element
Multi – Pointer to an array

void process( int (*ary)[20] ); // ptr to array of 20 ints
void process( int ary[][20] ); // same but clearer

void process_2d( int *a, int n, int m ) { // a is an n by m array
for( int i = 0; i < n; ++i )
for( int j = 0; j < m; ++j )
a[i*m+j] = 0; // calculate index by hand
}

// use template to make things cleaner

template
inline void process( int (&ary)[n][m] )
{ process_2d( &ary[0][0], n, m);}

Item 7 – Const Pointers and Pointers to Const
T *pt = new T; // ptr to T
const T *pct = pt; // ptr to const T
T *const cpt = pt; // const ptr to T

const T *p1; // ptr to const T, traditioal
T const *p2; // same

* Common Error *
T const *p3; // ptr to const
T *const p4 = pt; // const ptr to non-const

const T *const cpct1 = pt; // everything is const
T const *const cpct2 = cpct1; // same

It is often simpler to use a reference in preference to a const pointer.

const T &rct = *pt; // rather than const T *const
T &rt = *pt; // rather than T *const

Item 8 – Pointers to Pointers
- “multilevel” pointer

int *pi; // a ptr
int **ppi; // two level multilevel ptr
int ***pppi; // a three level multilevel ptr

Shape *picture[MAX];
Shape **pic1 = picture;

// moves a pointer to refer to the next occurence of a character in a string:
// p – the value we want to change
void scanTo( const char **p, char c ) {
while( **p && **p != c )
++*p;
}

char s[] = “Hello, World!”;
const char *cp = s;
scanTo(&cp, ‘,’); // move cp to first comma

- safer process
void scanTo( const char *&p, char c ) {
while( *p && *p != c )
++p;
}

char s[] = “Hello, World!”;
const char *cp = s;
scanTo(cp, ‘,’); // move cp to first comma

* Common Misconception *
- conversion that apply pointers also apply to p
pointers to pointers

Circle *c = new Circle;
Shape *s = c; // fine

Circle **cc = &c;
Shape **ss = cc; // error

char *s1 = 0;
const char *s2 = s1; // OK
char *a[MAX]; // aka char **
const char **ps = a; // err

Item 9 – New Cast Operators
- old style casts can do terrible damage unnoticeably

char *hopeItWorks = (char*) 0x00ff0000; // old-style cast

typedef char *PChar;
hopeItWorks = PChar( 0x00ff0000 ); // function style/old style cast stll

New Cast Operators (4)
1) const_cast
– alllows you to add/remove const and volatile type qualifier

const Person *getEmployee() {…}
// …
Person *anEmployee = const_cast(getEmployee());
2) static_cast
– used for castings that are relatively portable across platforms
– commonly used to cast “down” an inheritance hierarchy from Base class pointer or reference toward a derived class.

Shape *sp = new Circle;
Circle *cp = static_cast( sp) ; // downcast

const Shape *getNextShape() { … }
//…
Circle *cp = static_cast(const_cast(getNextShape()));

3. reinterpret_cast
– often necessary in low level code but it is not likely portable.
– will typically just pretend the base class pointer is a derived class pointer while a static cast will perform the correct
address manipulation
hopeItWorks = // pretend int is a pointer
reinterpret_cast(0x00ff0000);
int *hopeless = // pretend char* is int *
reinterpret_cast(hopeItWorks);
4. dynamic_cast
– used typically to perform a safe down cast from a pointer to a based to a derived class.

const Circle *cp = dynamic_cast(getNextShape());
if( cp ) { … }

if(const Circle *cp = dynamic_cast(getNextShape())) { … }

Item 10 – Meaning of a Const Member Function\
- The this pointer in a non-const member function of a class X is X* const.

class X {
public:
X(): buffer_(0), isComputed_(false) {}
// ..
void setBuffer() {
int *tmp = new int[MAX];
delete [] buffer_;
buffer_ = tmp;
}
void modifyBuffer( int index, int value ) const // immoral
{ buffer_[index] = value; }
int getValue() const {
if( !isComputed_ ) {
computedValue_ = expensiveOperation(); // error
isComputed_ = true; // error
}
return computedValue_;
}
private:
static int expensiveOperation();
int *buffer_;
bool isComputed_;
int computedValue_;
};

int getValue() const {
if(isComputed_) {
X * const aThis = const_cast(this); // bad idea
aThis->computedValue_ = expensiveOperation();
aThis->isComputed_ = true;
}
return computedValue_;
}

- the proper way is to make the data members mutable.
class X {
public:
// ...
int getValue() const {
if( !isComputed_ ) {
computedValue_ = expensiveOperation(); // fine
isComputed_ = true; // also fine
}
return computedValue_;
}
private:
//...
mutable bool isComputed_;
mutable int computedValue_;
};


class X {
public:
//...
X operator+( const X &rightArg ); // left arg is non-const
X operator+(const X &rightArg ); // left arg is const
};

Item 11 – The Compiler Puts Stuff in Classes
- most C++ programmers know that if a class declares one or more virtual functions, then the compiler will insert in each object of that class a pointer to a virtual function table.

POD – Plain Old Data (guaranteed not to be rearranged by the compiler)
struct s { // a POD-struct
int a;
double b;
};

Non-POD
struct s {
int a;
double b;
private:
std::string c; // some maintenance
};

- never make assumptions about the internal structure of your classes!

Item 12 – Assignment and Initialization Are Different
* 1/2 Assignment *
– occurs when you assign
– somewhat like destruction then followed by a construction
* 2/2 Initialization *

int a = 12; // initialization, copy 0x000C to a
a = 12; // assignment, copy 0x000C to a

Don’t do the following:
String *names = static_cast(::operator new( BUFSIZ ));
names[0] = “Sakamoto”; // oops! delete [] uninitialized pointer!

Item 13 – Copy Operations
- Copy construction and copy assignment are different operations.

class Impl;
class Handle {
public:
//...
Handle( const Handle &); // copy ctor
Handle &operator= (const Handle &); // copy assignment
void swap( Handle &);
//...
private:
Impl *impl; // pointer to implementation of handle
};

An implementation of a typical non-member swap
template
void swap(T &a, T &b ) {
T temp(a); // T's copy ctor
a = b; // T's copy assignment
b = temp; // T's copy assignment
}

// enhanced function
inline void Handle::swap(Handle &that)
{ std::swap( impl_; that.impl; }

Handle &Handle::operator = (const Handle & that) {
Handle temp( that ); // exception safe copy con
swap(temp); // exception safe swap
return *this;
}

A more common implementation of copy assignment:

Handle &Handle::operator=( const Handle &that ) {
if( this != &that ) {
// do assignment
}
return *this;
}

Item 14 – Function Pointers
- used traditioally for implementing callback functions
-
void (*fp)(int);

extern int f( int );
extern void g( long );
extern void h( int );
//…
fp = f; // error! incompatible
fp = g; // error! incompatible
fp = 0; // set to null
fp = h; // OK
fp = &h; // OK, take address explicitly but not necessary

(*fp)(12); // explicit dereference but not necessary
fp(12); // implicit

* A Callback Function *
extern void stopDropRoll();
inline void jumpIn() { … }
//…
void (*fireaction)() = 0;
//…
if( !fatalist ) { //
if( nearWater )
fireaction = jumpIn;
else
fireaction = stopDropRoll;
}

if( ftemp >= 451 ) { // If there is a fire
if( fireaction ) // .. and an action to execute
fireaction(); // .. execute it
}

It is also legal to take the address of an overloaded function:
void jumpIn() // gets selected
void jumpIn( bool canSwim );
// …
fireAction = jumpIn;

Item 15 – Pointers to Class Members Are Not Pointers
int *ip; // pointer to an int
int C::*pimC; // pointer to an int member of C

// a regular pointer
int a = 12;
ip = &a;
*ip = 0;
a = *ip;

class C {
public:
//…
int a_;
};

int C::*pimC; // pointer to an int member of C
C aC;
C *pC = &aC; // does not give us an address; it gives us an offset
aC.*pimC = 0;
int b = pC->*pimC;

* A pointer to a data member is not a pointer to an object; it’s an offset into an object
class Shape {
//…
Point center_;
//…
};

class Circle : public Shape {
//…
double radius_;
//…
};

Point Circle::*loc = &Shape::center_; //OK, base to derived
double Shape::*extent = &Circle::radius_; // error! derived to base

Item 16 – Pointers to Member Functions Are Not Pointers
- the address of a non-static member function does not give you an address, it gives you the pointer to the member function
-
class Shape {
public:
//…
void moveTo( Point newLocation );
bool validate() const;
virtual bool draw() const = 0;
//…
};
class Circle : public Shape {
//…
bool draw() const;
//..
};
//…
void (Shape::*mf1)( Point ) = &Shape::moveTo; // not a pointer
bool (Shape::*mf2)() const = &Shape::validate;

Circle circ;
Shape *pShape = ˆ
(pShape->*mf2)(); // call Shape::validate
(circ.*mf2)(); // same

mf2 = &Shape::draw; // draw is virtual
(pShape->*mf2)(); // call Circle::draw

class B {
public:
void bset( int val ) { bval_ = val; }
private:
int bval_;
};

class D {
public:
void dset( int val ) { dval_ = val; }
private:
int dval_;
};

B b;
D d;
void (B::*f1)(int) = &D::dset; // error! derived func in base ptr
(b.*f1)(12); // oops! access nonexistent dval member!
void (D::*f2)(int) = &B::bset; // OK, base func in derived ptr
(d.*f2)(11); // OK, set inherited bval data member

Item 17 – Dealing with Function and Array Declarators
int *f1(); // function that returns int *
int (*fp1)(); // ptr to a function that returns int

const int N = 12;
int *a1[N]; // array of N int *
int (*ap1)[N]; // ptr to array of N ints
int (**ap2)[N]; // ptr to ptr to array of N ints

Item 18 – Function Objects
Item 19 – Commands and Hollywood
Item 20 – STL Function Objects
Item 21 – Overloading and Overriding Are Different
- Nothing in common. Entirely different concepts.

Overloading
- occurs when two or more functions in the same scope have the same function name but different signature

Overriding
- occurs when a derived class function has the same name and signature as base class virtual function.

class B {
public:
//…
virtual int f( int ); // bad code
void f( B* ); // bad code
// ..
};

Bad code
- do not overload a virtual function
- do not overload on both integral and a pointer type.

class D : public B {
public:
int f( int ); // overrides the Base class function
int f(B*); // doesn’t override anything
};

Item 22 – Template Method
- If you don’t like the contract specified by the Base class, find a different base class. Don’t attempt to rewrite its contract.
- an example of the Hollywood principle. “Don’t call us, we’ll call you.”

class App {
public:
virtual ~App();
//…
void startup() { // template method
initialize();
if( !validate() )
altInit();
}
protected:
virtual bool validate() const = 0; // we’ll call you
virtual void altInit(); // we’ll call you
//…
private:
void initialize();
//…
}:

class MyApp : public App {
public:
//…
private:
//…
void validate() const;
void altInit();
//…
};

Item 23 – Namespaces

// wrong

#include
#include
using namespace std;
using namespace org_semantics;
- This is a bad idea.. All the names from the namespace is available everywhere..

// right
void aFunc() {
using namespace std;
// ..
int vector = 12; // a poorly named local variable
vector a; // error! std::vector is hidden
std::vector b; // OK, can use explicit qualification

}

* way to deal with long, tedious namespace name is to use an alias
namespace S = org_semantics;

Item 24 – Member Function Lookup

Item 25 – Argument Dependent Lookup

Item 26 – Operator Function Lookup

// A class that overloads an operator as a member function
class X {
public:
X operator %( const X & ) const; // binary modulus
X memFunc1( const X & );
void memFunc2();
//…
};

X a, b, c;
a = b % c; // infix call to member operator %
a = b.operator %( c ); // member function call
a = b.memFunc( c ); // another

X operator %( const X &, int ); // non-member operator
//…
void X::memFunc2() {
*this % 12; // calls non-member operator %
operator %( *this, 12 ); // error! To many args
}

Item 27 – Capability Queries
class Shape {
public:
virtual ~Shape();
virtual void draw() const = 0;
//…
};
//…
Shape *s = getSomeShape(); // get a shape, and tell it
s->draw(); // to work

// an interface class
- a class with no non-static data members
- no declared constructor
- a virtual destructor
- with a set of pure virtual functions

class Rollable {
public:
virtual ~Rollable();
virtaul void roll() = 0;
};

// Circles Roll
class Circle : public Shape, public Rollable {
//…
void draw() const;
void roll();
//…
};

// Squares dont
class Square : public Shape {
//…
void draw() const;
//…
};

In C++, capability query is
- typically expressed as a dynamic_cast between unrelated types.
- dynamic_cast is often called “cross-cast”
- it checks whether an object implements the Rollable interface, dynamic_cast will fail if s refers to a Square.

Shape *s = getSomeShape(); // will succeed
Rollable *roller = dynamic_cast(s);

Is this Shape Rollable?

“May I tell this shape to roll?”

Shape *s = getSomeShape();
if( Rollable *roller = dynamic_cast(s) )
roller->roll();

* Capablity queries are occasionally required, but they tend to be overused.
* Often an indicator of bad design.
* Best to avoid making runtime queries

Item 28 – Meaning of Pointer Comparison
“a question about object entity”
- an object can contain multiple, valid addresses
class Shape {…};
class Subject {…};
class ObservedBlob : public Shape, public Subject { … };

ObservedBlob *ob = new ObservedBlob;
Shape *s = ob; // predefined conversion
Subject *s = ob; // predefined conversion

if( ob == s ) … // works fine, true
if( subj == ob ) … // works fine, true

- Pointers to void are common culprits.
void *v = subject;
if( ob == v ) // not equal

Item 29 – Virtual Constructors and Prototype
- a member function that provides the ability to clone an object is traditionally called a “virtual constructor”.
- called “an instance of the Prototype pattern”

class Meal {
public:
virtual ~Meal();
virtual void eat() = 0;
virtual Meal *clone() const = 0; // a factory method
//…
};

// Concrete classes must provide an implementation of the pure virtual clone operation.
class Spaghetti {
public:
Spaghetti( const Spaghetti & ); // copy ctor
void eat();
Spaghetti *clone() const
{ return new Spaghetti( *this ); } // call copy ctor
//…
};

- we can now create a meal without precise knowledge of the type of meal

const Meal *m = thatGuysMeal(); // whatever he is eating
Meal *myMeal = m->clone(); // .. I have a meal same with the other guy

Advantage of ignorance in software design…
- “The less you know, the better”

Item 30 – Factory Method
- one common approach that is always wrong is the use of a type code and a switch statement
- the essence of FM is that the base class provide a virtual function hook (e.g. genInfo() ), for generating an appropriate “product”.
- often the cure for a series of runtime type check queries.

class Employee {
public:
enum Type { SALARY, HOURLY, TEMP };
Type type() const { return type_; }
//...
private:
Type type_;
//...
};

HRInfo *genInfo( const Employee &e ) {
switch( e.type()) {
case SALARY:
case HOURLY: return new StdInfo( e );
case TEMP: return new TempInfo( static_case (e) );
default: return 0;
}
}

The use of dynamic_cast to ask a series of personal questions of the Employee object is bad.

HRInfo *genInfo( const Employee &e ) {
if( const Salary *s = dynamic_cast(&e) )
return new StdInfo( s );
else if( const Hourly *h = dynamic_cast(&e) )
return new StdInfo( h );
else if( const Temp *t = dynamic_cast(&e) )
return new TempInfo( t );
else
return 0; // unknown employee type
}

The problem in the above code is the coupling to the concrete types. To fix the problem:

class Employee {
public:
//...
// Factory Method - virtual, abstract class
virtual HRInfo *genInfo() const = 0;
//...
};

class Temp : public Employee {
public:
//...
TempInfo *genInfo() const
{ return new TempInfo( *this ); }
//...
};

“Whatever type of employee you are, generate the appropriate type of information for yourself”

Employee *e = getAnEmployee();
//...
HRInfo *info = e->genInfo(); // use factory method

Item 31 – Covariant Return Types

Item 32 – Preventing Copying

class NoCopy {
public: NoCopy(int)
// ..
private: NoCopy(const NoCopy &); // copy ctor
private: NoCopy &operator= (const NoCopy &); // copy assignment
};

- this prevents the compiler to generate implicitly copy ctor and copy assignment.

void aFunc(NoCopy);
void anotherFunc(const NoCopy &);
NoCopy a(12);
NoCopy b(a); // error! copy ctor
NoCopy c = 12; // error! copy assignment
a = b; // error! copy assignment
aFunc(a); // error! pass by value with copy ctor
aFunc(12); // error! implicit copy ctor
anotherFunc(a); // Ok, pass by ref
anotherFunc(12); // Ok

Item 33 – Manufacturing Abstract Bases

// an example of an Abstract Base Class
class ABC {
public:
virtual ~ABC();
virtual void anOperation() = 0; // pure
//…
};

// another example of an Abstract Base Class that does
// not have virtual function yet a candidate as a Base Class

class ABC {
public:
virtual ~ABC();
protected:
ABC();
ABC(const ABC &);
// …
};

class D: public ABC {
// …
};

This codes prevents the creation of standalone ABC objects.

void func1(ABC);
void func2(ABC&);
ABC a; // error! protected default ctor
D d; // OK
func1(d); // error! protected copy ctor
func2(d); // Ok, no copy ctor , passed by ref

- second approach
class ABC {
public:
virtual ~ABC()=0;
//…
};
//…

ABC::~ABC(){…}
- destructor is often a good choice to make the class as abstract

- third approach
when a class has no virtual functions at all, and no need for explicitly declared constructors, a protected virtual destructor is good

class ABC {
protected:
~ABC();
public:
//…
};

the code above has the same effect as a protected constructor, but the error occurs when the object goes out of scope or destroyed expicitly.

Item 34 – Restricting Heap Allocation
- Benefits -
1. To ensure that the destructor is always called.
2. Local objects with auto storage class will have their destructor called automatically. (except in abnormal scenes like exit and abort )

class NoHeap {
public:
//...
protected: // may be declared as private if not intended to be use as base class.
void *operator new( size_t ) return 0;}
void operator delete( void * ) {}
private:
void *operator new[]( size_t );
void operator delete[]( void * );

};

thus calls to allocate object will result to compile-time error.

NoHeap *nh = new NoHeap; // error! protected NoHeap::operator new
//…
delete nh; // error! protected NoHeap::operator delete

Item 35 – Placement New
- a trick the compiler into calling a constructor for us
- a standard, global overloaded version of operator new that cannot be replaced with a user-defined version
void *operator new( size_t, void *p ) throw()
{ return p; }

You can refer to C++ Faq Lite for more details.

Item 36 – Class-Specific Memory Management
- you can implement operator new/detete to customize your needs, which are static members

class Handle {
public:
//…
void *operator new( size_t );
void operator delete( void * );
//…
};

//…
Handle *h = new Handle;
//…
delete h;

class MyHandle : public Handle {

};

Item 37 – Array Allocation

Item 38 – Exception Safety Axioms

Item 39 – Exception Safe Functions

Item 40 – RAII

Item 41 – New, Contructors, and Exceptions

Item 42 – Smart Pointers
- A class type that is tricked up to look and act like a pointer but that provides additional capability beyond that provided by a
built-in pointer.
- All SP overload the -> and * operators so that they can be used with standard pointer syntax.
- SP are often implemented as class templates so that they may refer to different types of objects.

template
class CheckedPtr {
public: explicit CheckedPtr(T* p) : p_(p) {}
public: ~CheckedPtr() { delete p_; }
public: T* operator ->() { return get(); }
public: T& operator*() { return get(); }
private: T * p_; // what we're pointing to
private: T* get() {
if(!p_) // check pointer before returning it
throw NullCheckedPointer();
return p_;
}
private: CheckedPtr(const CheckPtr &);
private: CheckedPtr &operator = (const CheckedPtr &);
};

CheckedPtr s (new Circle);
s->draw; // same as (s.operator->())->draw();

- SP also typically overload operator * as well as operator -> so that they may be used to refer to non class types.
CheckedPtr ip = new int;
*ip = 12; // same as ip.operator *() = 12;
(*s).draw(); // use on ptr to class, too

Item 43 – auto_ptr Is Unusual
- RAII
- a resource handle template that serves many resource handle needs
- it overloads operator-> and operator *
- it is very efficient (1)
- its destructor will free whatever it is pointing to (2)
- it behaves like a built-in pointer (3)

using std::auto_ptr;
auto_ptr aShape ( new Circle );
aShape->draw(); // draw a Circle
(*aShape).draw(); // draw it again

auto_ptr aCircle( new Circle );
aShape = aCircle; // valid

2 Situations where auto_ptr should be avoided:
1) Don’t use as container elements
2) auto_ptr should refer to a single element, not an array because when the object which the auto_ptr refers is deleted,
it will be deleted via operator delete, not array delete.

vector<auto_ptr > shapes; // likely error, bad idea
auto_ptr ints ( new int[32] ); // bad idea, no error (yet)

- A standard vector or string is a reasonable alternative to an auto_ptr to an array

Item 44 – Pointer Arithmetic
- simple and straightforward
- there is no pointer arithmetic available on void *

const int MAX = 10;
short points[MAX];
shot *curPoint = points+4;

** One Dimensional **

const int ROWS = 2;
const int COLS = 3;
int table[ROWS][COLS]; // array of ROWS arrays of COLS ints
int (*ptable)[ROWS][COLS] = table; // pointer to array of COLS ints

STL iterators also permit pointer-like arithmetic operation like the built-in pointers.

int a[] = {1,2,3,4};
std::list lst (a, a+3 );
std::list::iterator iter = lst.begin();
++iter;

Item 45 – Template Terminology

template typename // T is a template parameter
class Heap { … };
//…

Heap heap; // double is a template argument

template // typename T is a template-parameter list
class Heap; // Heap is the template name
template
class Heap // Heap is the template-id
template
class Heap // char * is the template-argument list
//…
Heap aHeap; // like char *
Heap aHeap2; // Heap is a template-id
template
void print (const T &x ) { … // print is a template-name

Template instantiation:
- when the primary heap template is used,or partial, an instantiation will take place
Template specialization:
- is what you get when you supply a template with a set of template arguments.
- can be implicit or explicit
// Heap is explicit
// print(12.3) is implicit

Item 46 – Class Template Explicit Specialization
-

Item 47 – Template Partial Specialization

Item 48 – Class Template Member Specialization

Item 49 – Disambiguating with Typename

Item 50 – Member Templates

Item 51 – Disambiguating with Template

Item 52 – Specializing for Type Information

Item 53 – Embedded Type Information

Item 54 – Traits

Item 55 – Template Template Parameters

Item 56 – Policies

Item 57 – Template Argument Deduction

Item 58 – Overloading Function Templates

Item 59 – SFINAE
- Substitution Failure Is Not An Error by Vandevoorde and Josuttis

Item 60 – Generic Algorithms
- a function template that is designed in such a way that it can be easily and effectively customized at compile time according to the context of its use.

// not a proper gen algo
– sorting is Slow, better use String’s own swap method

template
void slowSort(T a[], int len) {
for(int i = 0; i < len; ++i) // for each pair
for(int j = 0; j < len; ++j)
if(a[j] < a[i]) { // ... if out of order
T tmp(a[j]);
a[j] = a[i];
a[i] = tmp;
}
}

String names[] = { "my", "dog", "has", "fleece" };
const int namesLen = sizeof(names)/sizeof(names[0]);
slowSort(names, namesLen);

// right


template
void slowSort(T a[], int len) {
for(int i = 0; i < len; ++i) // for each pair
for(int j = 0; j < len; ++j)
if(a[j] < a[i]) { // ... if out of order
swap(a[j],a[i]); // ... swap them
}
}

inline void swap(String &a, String &b)
{ a.swap(b);}

class State {
/// …
public: int population() const;
public: float aveTempF() const;
// …
};

// best – more standard and more flexible STL compliant iterator interface

template
void slowSort( For b, For e, Comp less ) {
for( For i(b); i != e; ++i) // for each pair
for(For j(i); j != e; ++j)
if( less(a[j], a[i])) // … if out of order
swap(a[j], a[i]); // … swap them

}

template
void slowSort(For b, For e) {
for( For i(b); i != e; ++i) // for each pair
for(For j(i); j != e; ++j)
if( a[j] < a[i]) // … if out of order
swap(a[j], a[i]); // … swap them

// …
std::list states;
// …
slowSort(states.begin(), states.end(), PopComp());
slowSort(names, names + namesLen);
// …

Item 61 – You Instantiate What You Use
template
class Array {
public: Array() : a_(new T[n]) {}
public: ~Array() { delete [] a_;}
public: Array(const Array &);
public: Array &operator = (const Array &);
public: void swap(Array &that) { std::swap(a_, that.a_); }
public: T &operator[](int i) { return a_[i];}
public: const T &operator[](int i) {return a_[i];}
public: bool operator ==(const Array &rhs) const;
public: bool operator != (const Array &rhs) const;
};

template
bool Array::operator==(const Array &rhs) const
{
for(int i = 0; i < n; ++i)
if( !(a_[i] == that.a_[i])
return false;
return true;
}

Array a, b;
if(a == b) // calls a.operator ==(b)
// ...

The template member function will never be instantiated if there is no call on the template member functions. This thus reduces code size.

For types that does not override the == operator, there will be a problem.. for example,

Array c,d; // no problem
//…
c[3].draw(); // OK, we are not yet calling == operator

if(c == d) // error, because there is no overload of == operator in class Circle..

Item 62 – Include Guards
- preventing the content of a header file from appearing more than once in a compilation no matter how many times the header file is actually #included.

* in .h file
#ifndef HDR1_H
#define HDR1_H
..

#endif

* in .cpp file
#ifndef HDR1_H
#include “hdr1.h”
#endif
– rather than #include a header file, there is a guard in the inclusion with a test on the same guard symbol that is set within the header file. This is redundant, because the first time a header file is include, the same condition will be tested twice, both before the #include and within the header file itself.
- use of redundant include guards is not as common as that of simple include guards, but in some case their use can improve the
compilation time of large applications considerably.

Item 63 – Optional Keywords
* one source of confusion is the optional use of virtual in a derived class member function that overrides a base class virtual member function.

class Shape {
public: virtual void draw() const = 0;
public: virtual void rotate(double degrees ) = 0;
public: virtual void invert() = 0;
};

class Blob : public Shape {
public: virtual void draw() const;
public: void rotate(double); // misassumption that omitting the virtual keyword will prevent further overriding in more derive
// classes
public: void invert() = 0;
};

class SharpBlob : public Blob {
public: void rotate(double); // overrides Blob::rotate without the keyword virtual (misassumption)
};

* Omitting the virtual keyword
– some authorities claim that use of the nonessential virtual helps to document the nature of the derived class
– others claim it is a waste of effort and may cause a nonoverriding derived class function to become accidentally virtual

* another source of confusion is the static keyword
– the static keyword is optional when declaring member operator new, operator delete, array new, and array delete because these
functions are implicitly static

class Handle {
public: void *operator new(size_t); // implicitky static
public: static void operator delete(void *);
public: static void *operator new[](size_t);
public: void operator delete[](void*); // implicitly static
};

* keywords typename and class in a template header
– many expert c++ programmers use typename to indicate to the human reader that the template argument may be of any type and class to indicate that the type argument must be a class type.

template
Out copy(In begin, In end, Out result);

template
void resize(Contatiner &container, int newsize);

* keyword register
– in ancient times it is used to “suggest” to the compiler that a variable was (in the opinion of the programmer) going to be heavily used and should be therefore be put in the register
– in C++, use of register has “NO EFFECT” whatsoever on the efficiency of the program.

* keyword auto
– to indicate automatic variable or function

- keyword register and auto can be used in obscure circumstances to disambiguate the syntax particularly poor written code.
- avoid the use of these keywords
— FIN —

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s