Brace yourselves, pointers are coming. Usually, they’re one of the most frightening monsters you’re gonna encounter in your C/C++ adventure. However, once you learn how to use them, you will be able to see one of the biggest powerful pillar of C/C++. In this article, I’m gonna briefly teach you some features of pointer: Basic description,void* pointers, nullptr literal,const pointers, references, and rvalue references.

Pointers (equivalent to Java references) are part of the basic language mechanisms for referring memory. Mainly, they allow us to pass potentially large amounts of data with low cost. Despite this, there is high risk of memory corruption if they’re implemented incorrectly. Therefore, some implementations could be better to implement with STL containers instead pointers.One special feature of STL containers is their implementation to have more control over the object addressing, and hence preventing memory corruption.

Above all, the principal advantage of using pointer is that we can refer the address of a specific object, instead of passing the whole object (that could be very expensive).

The pointer’s principal operation is indirection (dereferencing unary prefix operator *) that permits us to referring the object pointed by the pointer. Besides indirection, there is the address-of operator &, which allows us to obtain directly the address of a specific object. To illustrate, there is the next snippet that teach you how to use the indirection and address-ofoperators:

char c='b';
char* n=&c; //n holds the address of c; & is the address-of operator

cout<<"n: "<<n<<endl; //address of c
cout<<"*n: "<<*n<<endl; //Value of c

void* Pointer

In low-level code, the void* pointer is used where we need to address an unknowing typevariable. Notice that, this type of pointer can’t serves as a function argument or a pointer to a class member, hence some operations (dereference and increment/decrement) can result in compile-time errors. Lastly, void* can be explicitly converted to another type when the case demands. For illustration, there is a function that try to use the dereference and increment operator in void* pointer,and in the end we explicitly convert back the void* to a int*:

void foo(int* pi){

    void* pv=pi;
    // cout<<*pv<<endl;  void* is not a pointer to object type
    //cout<<pv++<<endl; incrementing void* forbidded
    int* pi2=static_cast<int*>(pv); //Explicit conversion to int* back
    cout<<*pi2<<endl;
}

nullptr Literal

When we don’t require a pointer to point to an object, we should use the nullptr literal. The reason of this is that nullptr makes code more readable and avoids potential confusion in pointer’s implementation. Before the existence of the nullptr literal, zero(0) and NULL(used in C) were used as a notation to the null pointer, and creating a lot of misunderstanding.Lastly, I have to mention that, this literal ought to be used only with pointers.

Const Pointers

In C++, there are two related meanings of “constant”:

  • constexp, evaluate and ensure constness at compile time.
  • constdetermine variable immutability in a specific scope.

Using const pointers can be useful when we wanna prohibit any modification of a pointed object that is used as a function argument. For example, the next code shows 4 ways to use const with pointers:

//Illustrate the use of constness in pointers
    int a=15;
    const int b=16;
    int c=17;

    int* pi=&a; //pointer

    const int* cOp=&b; //is a pointer to a const int

    const int* const cOcP=&b; //is a const pointer to a const int

    int* const OcP=&a; //is a const pointer to a int

    //Okay let's play...
    /*Const pointer means that we're not able 
    to point the pointer to another variable*/

    //cOcP=&a; error: assignment of read-only variable
    cOp=&c; //(Y)

    //Now try to change the const variable

    //*cOcP=17; error: assignment of read-only variable
    *OcP=17; //(Y)

References Alias

reference is an alias for an object, but in contrast with pointers, it doesn’t impose performance overhead, and holds the same syntax as the name of its object.

The principal use of references is to specify effective parameters and return values for functions. In other words, there could be large objects that are expensive to pass by value to a function (actually, we’re not passing the “original” object, but copying it); so a reference parameter is initialized by the actual argument that is passed when the function is called avoiding the copy of itself.

A better approach than a reference parameter, is a reference to a const parameter. By this way, we’re telling the compiler to make sure that the functions does not attempt to change that object. This, believe me… may save you a few days of stress looking for bugs.

As a illustration, I’m showing a elegant function declaration (which use reference to a const) that is part of a Crypto program I had developed; this function change the value of each character of a string based on a special key:

//We ensure no change in the argument value using pointer to const value
QString Crypto::unshift(const QString& str){ //!!
 
  QByteArray ba=str.toLocal8Bit();
 
  for(int i=0;i<ba.size();i++)
    ba[i]=ba[i]-m_usKey;
 
  QString temp(ba);
  return temp;
}

EXTRA Rvalue References

With the purpose of encourage your curiosity… What’s the most effective swap function?

void oldSwap(string a,string b){
    string temp{a};
    a=b;
    b=temp;
}

void swap(string a, string b){
    string temp{static_cast<string&&>(a)};
    a=static_cast<string&&>(b);
    b=static_cast<string&&>(temp);
}

That’s it!

Leave a Reply

Your email address will not be published. Required fields are marked *