kenics.net

Technical notes on perl, python, php, sql, cgi, c/c++, q/kdb+, unix/shell, revision control tools, data structures & algorithms, and their applications into web services and other various forms of software engineering.

C++ pointer and reference

 
############################## 
####  pointer/reference   #### 
############################## 
 
instead of accessing the object directly, we dereference the object by its address. 
this lets us manipulate the data over different segments of the code, over diff threads, etc. 
because diff functions' objects will have diff place within program stack. so if you pass an object without a pointer, the receipient function will create a copy. but pointer lets you access the same object property. 
// also, this is less significant today, but a pointer lets you avoid copying of objects, meaning you can save mem space. 
 
int val = 1024; 
int *num = &val; 
// num = &val; 
// num = 0;      // initialize the pointer. a null pointer. 
if (!num)        // good way to check if a pointer is null or not. 
cout << *num;    // print 1024 
count << num;    // print 0x7fffb0404040 
 
 
 
------ 
int *pi; 
pi = new int;       //  this gets an address for 4-byte mem from heap(free mem space for dynamic allocation), just like malloc() 
// pi = new int();  //  this is the same as the above line. as you will see below, it's used when you want to pass val into constructor 
*pi = 1024; 
----- 
int *pi = new int(1024);    // this is the same as above three lines 
 
delete pi;  // just like free(), null pointers are ignored, but freeing/deleting not allocated ptr will result in undefined behavior. 
 
int *piarr = new int[15]; 
delete [] piarr; 
 
 
piarr[2]      // these two mean the same 
*(piarr+2)    // so you can implement your for loop with piarr++ and *piarr in each iteration as below 
 
for (int i = 0; i < size ; i++) 
    cout <<  piarr[i] << ' '; 
 
for (int i = 0; i < size ; i++, piarr++) 
    cout << *piarr << ' '; 
 
---------------------------------- 
 
 
############################################## 
###   stack  VS  heap  -  mem allocation   ### 
############################################## 
 
int arr[15];              // mem gets allocated on the stack. auto-destroyed when exiting out of scope. 
int* arr = new int[15];   // mem allocated from the heap, and its pointer on the stack. 
                          // must explicitly free before the pointer gets auto-destroyed. (or pass to other ptr) 
 
(ref) 
http://www.cplusplus.com/forum/beginner/12755/ 
 
 
########################## 
###   new VS malloc()  ### 
########################## 
 
- new/delete is c++ version of malloc()/free(). malloc/free will just (de)allocate mem from heap. new/delete will also call constructor/destructor. 
- new/delete are operators (just like =,-,+, etc)(aka pre-processors) whereas malloc()/free() are functions. pre pro operator you can overload. 
- new is more type-safe (no need to do sizeof(type)+1 ) 
- new initializes the values to zero in the allocated mem. 
 
(ref) 
http://homepage2.nifty.com/assua/aosite/cpp/cpp_intro/cpb12.html 
http://stackoverflow.com/questions/807939/what-is-the-difference-between-new-and-malloc-and-calloc-in-c 
http://stackoverflow.com/questions/2983182/new-delete-malloc-free 
 
-------------------------------------------------- 
 
// C 
int *p = (int*)malloc(sizeof(int)); 
free(p); 
 
// CPP 
int *p = new int;    // int *p = new int(); 
delete p; 
 
// C 
int *p = (int*)malloc(sizeof(int) * 10); 
free(p); 
 
// CPP 
int *p = new int[10];                       // new[] is for an array of contiguous mem 
delete [] p;                                // delete[] 
 
// C 
struct Test{ 
   int n; 
   char ch; 
}; 
struct Test *p = (struct Test*)malloc(sizeof(struct Test)); 
free(p); 
 
// CPP 
struct Test{ 
int n; 
char ch; 
}; 
 
Test *p = new Test;    // Test *p = new Test(); 
delete p; 
 
--------------------------------------------------- 
 
 
 
############################### 
####      placement new     ###  - kind of like realloc() 
############################### 
 
new operator with a special overload. it lets you specify the mem addr to which you can allocate the mem chunk. 
 
the difference is the normal "new" allocates heap mem space whereas placement new will allocate the already available space thus faster. 
so code that does lots of "new" call might want to consider placement new. 
 
--------------------------------------------- 
#include <iostream> 
#include <new>                                  // to use placement new, #include <new>  is a must 
#include <cstring> 
using namespace std; 
 
char global_array[100]; 
 
int main() 

  char* cp = new(global_array) char[10];         // allocate char[10] space starting at global_array address 
  cp[0] = 'h'; 
  cp[1] = 'e'; 
  cp[2] = 'l'; 
  cp[3] = 'l'; 
  cp[4] = 'o'; 
 
  cout << cp << endl;                           //  "hello" 
 
  cout << global_array << endl;                 //  "hello" 
 
  return 0;                                     //  because placement new does not allocate heap memory, no need for explicit delete 

 
---------------------------------------------- 
 
but there is indeed placement delete for such cases as when you want to clean up the space once. but those are special setup, so you define overload operator for new and delete for your own usage. more example on the ref URL. 
 
 
(ref) 
http://www.geocities.jp/ky_webid/cpp/language/036.html 
 
 
############################################ 
###   pointer  VS  reference   example   ### 
############################################ 
 
below two are doing the exact same thing. but note a few points. 
- a pointer can be re-assigned but a reference cannot. 
- pointer can point to NULL but a reference must refer to an object. 
- cannot take the addr of reference, but can for pointer. 
- you can increment addr of pointer++, but not for reference. 
 
 
-------  pointer example  --------- 
 void func(int* piyo) { 
     *piyo = 10; 
 } 
 
 int main(void) { 
     int hoge = 0; 
     func(&hoge);                   // giving an address 
     return hoge; 
 } 
------------------------------------ 
 
-------  reference example  -------- 
 void func(int& piyo) {               // if no "&" then you cannot change hoge value, cos piyo will be a local copy. 
     piyo = 10; 
 } 
 
 int main(void) { 
     int hoge = 0; 
     func(hoge);                  // notice, this is just like giving the variable. very powerful. 
     return hoge; 
 } 
----------------------------------- 
 
 
-------------------------------- 
void display( vector<int> *vec ) 

    if(!vec){ 
        cout << "vec is a null pointer"; 
        return; 
    } 
    for (int i = 0; i < vec->size() ; i++) 
        cout << vec[i]; 
    cout << endl; 

 
int main() 

    int arr[3] = {23, 84, 93}; 
    vector<int> vec (arr, arr+3); 
 
    display( &vec ); 

-------------------------------- 
 
 
###################################### 
###   reference as a return type   ### 
###################################### 
 
a perfect example copy & paste from ref http://tinyurl.com/cmxc6g 
 
------------------------------------------- 
#include <iostream> 
 
class CSample 

public: 
CSample(){ m_num = 123; }    // initialization of its private member variable 
int& get(){ return m_num; }  // return a ref to its private member variable 
private: 
int m_num; 
}; 
 
int main() 

CSample obj; 
int& alias = obj.get();              // get a ref to an interger 
std::cout << alias << std::endl; 
 
alias *= 2;                          //  multiply by two 
std::cout << obj.get() << std::endl; //  print 246. interesting. 
return 0; 

--------------------------------------------- 
 
============>   you must have the below line in one line. 
 
int& alias = obj.get(); 
 
============>  cannot split into two. ref MUST be initialized when declared. 
 
int& alias;           // compile error. 
alias = obj.get(); 
 
 
 
 
############################## 
####    smart pointer     #### 
############################## 
 
(ref) 
http://99blues.dyndns.org/blog/2010/02/auto_ptr/ 
 
------------------------- 

T* p = new T(); 
 
if( hoge ){ 
return;    // seg fault 

 
delete p; 

------------------------- 
 
======> you can try try&catch exception handling OR use smart pointer 
 
 
------------------------- 
#include <memory>               // contains smart pointer 
 

std::auto_ptr<T> p(new T());    // smart pointer 
 
p->func(); 
 
if(hoge){ 
return;                     // smart pointer will automatically delete itself 

                                // smart pointer will automatically delete itself 

------------------------- 
 
 
ADD MORE DETAILS HERE from the above ref link 
 
 
 
 
###################################### 
####    a pointer to a function    ### 
###################################### 
 
can be complex cos you have to specify both (1) input param and (2) return data type 
 
but useful, e.g. for call back mechanism. 
 
Syntax:   <return_data_type> (*pointer_name)(input_param); 
 
e.g. 
------------------------------------ 
int func(const char* str);            // a normal func declaration 
int (*ptr_func)(const char*) = func;  // a pointer to func 
 
int a = (*ptr_func)("hello");         // this is how you invoke 
int b = ptr_func("hello");            // this is legit also 
------------------------------------ 
 
NOTE:  never forget the parenthesis around *ptr_func because if you write 
*ptr_func("hello")  ->  () has priority over *  so it will be corrupted 
 
 
 
example code 
------------------------------------ 
#include <iostream> 
using namespace std; 
 
int func(const int* x){return (*x) * 2;} 
 
int main() 

  int i = 123; 
  const int* pi = &i; 
  int (*pf)(const int*) = func; 
//int (*pf)(const int*) = &func;   //  confusingly enough. this is also legit. in fact, this makes more sense. 
 
  // int *pf(const int*);        // if you do this, pf will be treated as a func prototype that returns int* type. 
 
  cout << (*pf)(pi) << endl;     //  246 
  cout << pf(pi) << endl;        //  246  this is legit also 
 
  return 0; 

 
--------------------------------- 
 
 
########################## 
####    callback     ##### 
########################## 
 
###  CallBack   // C example 
 
(wikipedia) 
a callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time. The invocation may be immediate as in a synchronous callback or it might happen at later time, as in an asynchronous callback. 
 
The ways that callbacks are supported in programming languages differ, but they are often implemented with subroutines, lambda expressions, blocks, or function pointers. 
 
----------------------------------- without callback 
int i; 
 for (i = 0; i < length; i++) { 
     if (array[i] > 5) { 
         break; 
     } 
 } 
 
 if (i < length) { 
     printf("Item %d\n", i); 
 } else { 
     printf("Not found\n"); 
 } 
----------------------------------- 
----------------------------------- with callback 
/*  Library code  */ 
 int traverseWith(int array[], size_t length, 
                  int (*callback)(int index, int item, void *param), 
                  void *param) 
 { 
     int exitCode = 0; 
     for (int i = 0; i < length; i++) { 
         exitCode = callback(i, array[i], param); 
         if (exitCode) { 
             break; 
         } 
     } 
     return exitCode; 
 } 
 
 /* application code */ 
 int search (int index, int item, void *param)     // void*  generic pointer 
 { 
     if (item > 5) { 
         *(int *)param = index;                    // must cast explicitly like (int *) 
         return 1;                                 // this *(int*)param kind of casting/dereferencing you see all the time 
     } else { 
         return 0; 
     } 
 } 
 
 /* main code  */ 
 int index; 
 int found; 
 found = traverseWith(array, length, search, &index); 
 if (found) { 
     printf("Item found at index %d\n", index); 
 } else { 
     printf("Not found\n"); 
 } 
------------------------------------- 
 
 
(ref) 
http://www.geocities.jp/ky_webid/ProgrammingPlacePlus/c/037.html#function_pointer 
http://www.geocities.jp/ky_webid/cpp/language/030.html 
http://wisdom.sakura.ne.jp/programming/c/c47.html 
 
 
 
###################################### 
####    member function pointer   #### C++ 
###################################### 
 
pretty much like a normal function pointer, but need to specify the class scope class::func with an ampersand. an ampersand is a MUST unlike normal func ptr. 
since it's merely a pointer to a function, you can declare it even before any actual class object is instantiated. 
 
e.g. 
---------------------------------------------- 
#include <iostream> 
using namespace std; 
 
class CParent 

public: 
  CParent(){ num = 'z';} 
  int func(const int x){ return 2 * x ;} 
  char func2(){ return this->num ;} 
private: 
  char num; 
}; 
 
class CChild : public CParent 

public: 
  int func(const int x){ return 3 * x ;} 
}; 
 
int main() 

  int (CParent::*ptr_func)(const int) = &CParent::func; 
  char (CParent::*ptr_func2)() = &CParent::func2; 
 
  int i = 123; 
 
  CParent cp; 
  cout << cp.func(i) << endl;                               //  246 
  cout << (cp.*ptr_func)(i) << endl;                        //  246 
 
  cout << cp.func2() << endl;                               //  'z' 
  cout << (cp.*ptr_func2)() << endl;                        //  'z' 
 
 
  CParent* pcp = &cp;                                       // passed the addr to an instance 
  cout << pcp->func(i) << endl;                             //  246 
  cout << (pcp->*ptr_func)(i) << endl;                      //  246 
 
  cout << pcp->func2() << endl;                             //  'z' 
  cout << (pcp->*ptr_func2)() << endl;                      //  'z' 
 
 
  CParent* pcp_no_instance;                                 //  notice how we didnt pass &cp 
                                                            //  means no instance for this pointer 
  cout << pcp_no_instance->func(i) << endl;                 //  246   still works! 
  cout << (pcp_no_instance->*ptr_func)(i) << endl;          //  246   cos func() needs no instance to work 
                                                            // BUT, if CParent::func() was a virtual func, then this seg-faults, cos &CParent::func gives vtbl addr 
 
  cout << pcp_no_instance->func2() << endl;                //  seg-fault  !!!! 
  cout << (pcp_no_instance->*ptr_func2)() << endl;         //  seg-fault  !!!! char num is not initialized without an instance 
 
  CChild ch; 
  CParent* pcpch = &ch; 
  cout << pcpch->func(i) << endl;                           //  246    if the parent func() was declared "virtual" this will be 369 
  cout << (pcpch->*ptr_func)(i) << endl;                    //  246    if the parent func() was declared "virtual" this will be 369 
  cout << pcpch->CParent::func(i) << endl;                  //  246    regardless of "virtual" or not 
  cout << pcpch->CChild::func(i) << endl;                   //  error   cos CParent did not inherit CChild 
 
  cout << pcpch->func2() << endl;                           //  'z' 
  cout << (pcpch->*ptr_func2)() << endl;                    //  'z' 
 
  return 0; 

 
---------------------------------------------- 
 
 
if calling from the inside a class, then need to invoke (this->*ptr_func)() 
this->*   cannot me omitted. 
 
e.g. 
----------------------------------------------- 
class CParent 

public: 
void foo(); 
    void bar(); 
}; 
 
void CParent::bar() 

void (CParent::*pfoo)() = &foo;            //  ampersand is optional 
(this->*pfoo)();                           //  this->*   is mandatory 
    *pfoo();                                   //  error 

 
----------------------------------------------- 
 
 
##################################### 
###   member  variable  pointer   ### 
##################################### 
 
very similar to member func ptr.  not likely to be used extensively as it implies we make the member variable public, but still nice to note. 
 
e.g. 
------------------------------------ 
class CParent 

  public: 
    int val; 
}; 
 
int main() 

    int CParent::*p = &CParent::val;     // notice how we dont need parenthesis around CParent::*p 
 
    CParent cp; 
    cp.*p = 123; 
    (&cp)->*p = 321; 
 
return 0; 

 
------------------------------------ 
 
 
 
########################################## 
###   static member function pointer   ### 
########################################## 
 
 
just like a non-static member function pointer, but you dont need an instance nor class scope specifier. 
 
e.g. 
-------------------------------------- 
#include <iostream> 
using namespace std; 
 
class CParent 

public: 
  static void print(const char* str){ cout << str << endl;} 
}; 
 
int main() 

  //  void (CParent::*ptr_func)(const char*) = &CParent::print;     //  error 
  void (*ptr_func)(const char*) = &CParent::print;                  //  static existence not per particular instance, thus gotta use this generic func ptr. 
 
  CParent cp; 
  // (cp.*ptr_func)("hello");                                       //  error 
 
  cp.print("hello");                                                //  'hello' 
 
  ptr_func("world");                                                //  'world' 
  (*ptr_func)("foo_bar");                                           //  'foo_bar' 
 
  return 0; 

 
-------------------------------------- 
 
 
 
######################################## 
####     a pointer to a pointer     #### 
######################################## 
 
 
a normal pointer example 
 
---------------- 
 
int main(){ 
  int i = 123; 
  int* pi = &i; 
  multiply(pi); 

 
void multiply(int* pi){ 
   *pi *= 2; 

---------------- 
 
 
imagine you have a linked-list with nodes connected via pointers. then some of the func requires you to pass in a pointer to a pointer. 
 
---------------------------- 
 
#include <iostream> 
using namespace std; 
 
struct node{ 
  struct node* next; 
  int data; 
}; 
 
void add(node** p, int x);  // a forward declaration 
 
int main(){ 
 
  node* head = new node; 
  head->data = 123; 
  head->next = 0; 
  add(&head, 456); 
  add(&head, 789); 
 
  cout << head->data << endl;             // 123 
  cout << head->next->data << endl;       // 456 
  cout << head->next->next->data << endl; // 789 
 
  return 0; 

 
void add(node** p, int x){ 
  node* new_node = new node; 
  new_node->data = x; 
 
  node* tmp = *p; 
 
  while(1){ 
    if(!(tmp->next)){ 
      tmp->next = new_node; 
      break; 
    } 
    tmp = tmp->next; 
  } 
 

 
---------------------------- 
 
====> notice the use of  node** p  in add() input parameter. 
====> in short, if you simply pass a pointer var, like  node* p, within a function, then you only get a temp var. 
====> so while you can dereference to manipulate a value that the pointer points to, if you change the pointer itself (address), it's only valid within a function. 
====> hence the need for node** p 
====> the below stackoverflow link explains well with lots of example code. 
 
(ref) 
http://stackoverflow.com/questions/15244429/pointer-of-a-pointer-in-linked-list-append 
 
 
 
 
############################### 
####    more reference     #### 
############################### 
 
 
http://www.geocities.jp/ky_webid/cpp/language/034.html 
http://homepage2.nifty.com/well/Pointer.html 
http://www7b.biglobe.ne.jp/~robe/cpphtml/html03/cpp03057.html 
http://blog.keit.me/20120215/67/ 
http://sceneryandfish.withnotes.net/?p=1293       // member func ptr to a virtual func 
http://en.wikipedia.org/wiki/Virtual_method_table // hard-code explanation on vtbl 
 

  1. 2014-05-08 01:14:41 |
  2. Category : cpp
  3. Page View:

Google Ads