C++ Tips and Tricks

Unlike other object-oriented programming languages, C++, by far, is the most complex and powerful. The code structure can often be quirky and convoluted. Intriguingly, this tricky part keeps C++ programmers on their toes, sometimes even to the point of baffling a seasoned programmer. There is almost always room for fine tuning the code on every revisit. Many programmers who write code in other languages as a professional requirement love tinkering with C/C++, due to its bizarre and deviant style. The article shall deal with some not-so-obvious tips that often may have been overlooked or need refreshing.

1. Literals and Variables

A literal, typically, is a self-evident value of a certain type determined by its form. The type of the literal can be int, unsigned int, long, unsigned long, long long or unsigned long long according to the size of the value from smallest to largest, respectively. There is no short literal. For example,

  • 23 is a decimal literal, by default signed
  • 023 is a octal literal. Because it is prefixed by 0 (zero), can be signed or unsigned
  • 0x23 or 0X23 is a hexadecimal literal. Because it is prefixed by 0x or 0X, can be signed or unsigned
  • Floating point literals can be written as 1.2345f or using scientific (exponential) notation 1.2345E0 or 1.2345e0
  • ‘A’ is a character literal and
  • “Some text” is a string literal

There are suffixes (u/U – unsigned, l/L- long or long double, ll/LL- long long, f/F- double) for numeric literals and prefixes (u – 16-bit unicode character, U – 32-bit unicode character, L- wide character, u8 – utf-8 string literals) for character literals to override the meaning. Some valid literals are as follows:

L'A', u8"some text", 23E-10, 1.2324L, 78ULL

Now, what about -23? -23 is not a literal per se, but the ‘-‘ (minus sign) is an operator that negates the decimal literal 23.

Variables are named memory location where the size occupied is defined by the type associated. There are two types of values always associated with a variable: lvalue (memory location) and rvalue (read value). This is the main reason variables are addressable and literal constants are not, and we can write,

// iv has both lvalue and rvalue associated
// with the name.
int iv=5;
// cannot be written, because it is a literal
// constant.
5=iv; or 6=5;

But, what happens when we write:

iv = iv + 5;

Here, the variable at the left hand side is referred to have lvalue and the same variable at the right side of ‘=’ operator refers the rvalue. So, the rvalue of the variable +  literal, 5, is stored in the memory location named iv.

2. Initialization and Assignment

There is a subtle difference between initialization and assignment. Initialization refers to a value given to a variable at the time of its creation and assignment refers to the rvalue of a variable that is overwritten with some other value. For example,

// it is an initialization. It is a good programming
// practice to initialize a variable as soon as it is
// created.
int i=0;
// it is an assignment where initial value is
// overwritten with a new one.
i=10;

In C++ 11, a variable can be initialized in one of many ways, such as

int i={0};
int i{0};
int i(0);

3. The Tricky const Qualifier

The const qualifier has one purpose: to make the object unchangeable or constant. That means a constant can only be initialized and never assigned in C++. As should be obvious, the initialization must be done on creation. For example,

const double area=35.78f;

Now, suppose we declare a pointer that that holds the lvalue of an area:

// error! Pointer to a variable.
double *ptr_area=&area;

This is an erroneous statement because we had declared the area as a constant but left a room for assignment.

// error! Trying to change the constant value
ptr_area=6.56;

Thus, if we want to declare a pointer to point to a constant, we must declare a pointer that addresses a constant object, as follows.

// OK, pointer to a constant object
const double *ptr_area=&area;

Can a pointer to a constant object refer to a variable (not constant)? Certainly.

double area=35.78f;
const double *ptr_area=&area;   // OK
rea=11.56f;   // OK
*ptr_area=9.62f   // error!

A pointer to a constant object can refer to a non-constant variable but no assignment is allowed through the pointer.

In all the preceding cases, a declared pointer is a pointer to a constant object. What if we want to create a pointer that is itself a constant? In such as case, say,

double area=35.78f;
double another_area=98.34f;
// OK during initialization
double *const ptr_area=&area;
*ptr_area=77.56f; //OK

This is because the pointer is constant but the variable it points to is not a constant.

//error! Assignment not allowed.
ptr_area=&another_area;

So, it’s pretty obvious from all the previous statements, we can easily understand the following code:

const double area=35.78f;
const double *const pointer_area=&area;

Thus, it is a constant pointer to a constant area.

4. Validity Assertion

Assertions come in handy in checking the validity of an expression. This can be done with the help of the assert macro defined in the <cassert> header file. This is particularly useful as a debugging tool to test whether a variable has a correct value. If the value of the expression is 0 (false), an error message is printed, and then calls an abort function to terminate program execution. For example, suppose a variable, say maxsize, should never be greater than 1024 in a program. We can use assertion to test the value and print an error message if it’s incorrect.

#include<cassert>
int main()
{
   assert(maxsize<=1024);
}

 If the value is greater than 1024, an error message with the line number and file name is printed in the standard output before terminating the program. As it was said, it is helpful in debugging, but in case when we do not want to debug or disable assertion, we can insert the following line as the first line of the source code:

#define NDEBUG

Once this line is inserted, the assert macro will not work even if it is still in the code.

5. String Conversions

String conversion to an integer or vice versa is a common phenomenon of everyday programming. C++ 11 introduced some convenient wrappers for the purpose. For example, to convert an integer to a string, we may write the following:

#include<string>
int main()
{
   int ival=112233;
   string str=to_string(ival);
   return 0;
}

To convert a string to an integer, we may write the code as follows:

#include<string>
int main()
{
   string num_str="112233";
   int ival=stoi(num_str);
   long long llval=stoll(num_str);
   return 0;
}

Conclusion

The strongest column must have the strongest base. When one goes up the ladder of programming, these five concepts are very crucial. Feel free to comment on what other conceptual areas you as a programmer often revisit, relearn, or reread.

Manoj Debnath
Manoj Debnath
A teacher(Professor), actively involved in publishing, research and programming for almost two decades. Authored several articles for reputed sites like CodeGuru, Developer, DevX, Database Journal etc. Some of his research interest lies in the area of programming languages, database, compiler, web/enterprise development etc.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read