Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C++ Coding Culture - Part I

0.00/5 (No votes)
19 Apr 2005 1  
An article on C++ coding style, practices and discipline.

Introduction

Coding in C++ is an art, a passion. Many other languages like Java have absorbed the constructs of C++ because it is elegant. In my article, I shall discuss many styles, practices and discipline of coding C++. I have split the article into mutiple chapters and this chapter is about how to code elegantly to get rid of warnings.

Getting Rid Of Compiler Warnings

Always when you build your project, you must develop the habit of making it free of warnings. It is always a good practice to resolve the warnings because being lazy to resolve them or just being contended that the code just works fine will lead to dangers later. A successful build should be warning free. In this chapter, I'll discuss a few of the common warnings that the visual c++ compiler spits and how to solve them so that we get a successful build. The solution to resolve warnings is not switching it off but almost a slight modification in the code, else it may be a potential threat of a run-time danger. And not all warnings are dangerous at run-time but they are always a black spot.

1. VARIABLE DEFINED BUT NEVER USED

If the variable defined is not used ie not really needed then remove it. But this cannot be done always. Let us understand by example.

void func()
{
   // warning: "variable 'lv' is defined but never used"

   long lv;
}

Now take this case. Here we call a method SomeFunc that may throw an exception. If it does, then we catch it to safely handle the situation and just put out a trace message. But we get a warning that 'e' is not used. How do we solve this, simply use the variable as an expression.

void Fun()
{
   try
   {
      SomeFunc();
   }
   catch(MyException& e)
   {
      // warning: "variable 'e' is defined but never used"

      // Solution 1

      e;

      // Solution 2 - Use just MyException & without the e in the catch declaration above.


      // Solution 3 - use UNREFERNCED_PARAMETER(e);


      OutputDebugString("Exception Occurred");
   }
}

Moral: Always know that you have declared a variable and how and where you use that in your code.

2. VARIABLE NOT INITIALIZED

Many times, we declare int i or long k and directly use in that in loops or in some 'if' statements, and that is disasterous. Always initialize the variable to the best default that the situation demands. An int i need not be always initialized to 0 because may be i am going to do a reverse scan on an array of size 20.

Moral: Always know that you have declared a variable and how and where you use that in your code.

3. SIGNED/UNSIGNED MISMATCH

I have got this warning innumerble times. For example, the natural tendency of a programmer to store a numeric is as an int.

unsigned long GetMyNumber()
{
   long lv = 100;
   .
   .
   .
   return lv;
}

void main()
{   
   long x = 10;
   long y = 20;
   
   // signed/unsigned warning  

   if ( x == GetMyNumber())
   {
   }
   // signed/unsigned warning  

   else if ( y == GetMyNumber() )
   {
   }
}

Change the types of the variables being compared so that the types agree. If not apt for the situation, use an explicit static_cast. The cast operators in C++ is very good style and discipline to follow. In the above case, the compiler casts implicitly and issues a warning because :-

int c = -2;
unsignec int uc = 255;
if ( c < uc )
{
   cout << "Less Than";
}
else
{
   cout << "Not Less Than";
}

The above case will print not less than.

Moral: Know what the type and content of the variable represents and manipulate them accordingly.

4. MISSIGN RETURN

Consider the code below.

// compiler warning - missing return statement

int missingret(int age)
{
   if ( age <= 10 )
   {
      return 1;
   }
   
   if ( age > 10 && age <= 50 )
   {
      return 2;
   }
   
   if ( age > 50 && age < 500 )
   {
      return 3;
   }
}

The above logic might be ok for your employee program that says no employee must live more than 500 years. Even though that it is true, the compiler will not believe it and will warn you "what do i return if an employee is 600 years old". We may be sure that the control during the program execution will never reach the end of the function but the compiler is not and we have convince it by giving a return at the end of the function. Ultimately it is the compiler that compiles the code and not us, so better do it if you want to write elegant code this way:-

// compiler warning - missing return statement

int missingret(int age)
{
   int nRetVal = 0;

   if ( age <= 10 )
   {
      nRetVal = 1;
   }
   
   if ( age > 10 && age <= 50 )
   {
      nRetVal = 2;
   }
   
   if ( age > 50 && age < 500 )
   {
      nRetVal = 3;
   }

   return nRetVal;
}

Moral: Never assume that an employee will not live more than 500 years. Ensure that all control paths return [process] the correct value and not assume an unknown value at run-time.

5. UNREACHABLE CODE

This is a simple well-known warning.

int func()
{
   return 2;
   cout << "How can i reach here ??";
}

The cout statement in the above code is not reachable since we return 2 in any case. The above code is simpe snippet that illustrates the problem. We will encounter this in fucntions that have a complex logic involving many loops and decision statements, and in the go, we miss something that results in large code of code unreachable. For example, if a if block was in

Moral: Review the code thoroughly whenever a function has multiple return statements.

6. UNUSED FUCNTION PARAMETERS

It is better to remove the parameter if not really used but has been just put in place for a reason that you do not remember.

// warning for b -  better remove it.

int ManipulateString(const std::string& sText, bool b = false)
{
   sText.append("_Modified");
   return 0;
}

But sometimes in my project, i come across situations where i have to protoype the function with a parameter but that will be really useful only in my next version. In such cases, it syntax works out.

int ManipulateString(const std::string& sText, bool /*b*/ = false)
{
   sText.append("_Modified");
   return 0;
}

Later

int ManipulateString(const std::string& sText, bool b = false)
{
   if ( b == true )
   {
      sText.append("_Modified");
   }
   else
   {
      sText.append("_Modified_New Version");
   }
      
   return 0;
}

Moral: Ensure you have a parameter because you need it in the function, now or later. If it's not needed now, delete the name of the function parameter.

7. WARNINGS FROM THIRD PARTY FILES

My God, this has always been a war in my project. We use third party development headers in our project and we get a lot of warnings from those developement headers. On examining the code in the third party header, you may find some of the above warning cases that we discussed above but we are not supposed to change them. In such cases, i follow what Herb Sutter has suggested. Wrap the file with your own version that #include s the original header and selectively turns off the noisy warnings for that scope only, and then #include your wrapper throughout the rest of your project.

// File: myproj/MyTrace.h -- wraps third party TPTrace.h

//  Now include MyTrace.h where ever you need TPTrace.h. Don't use TPTrace.h directly.

// When they fix it we'll remove the pragmas below, but this header will still exist.

#pragma warning(push)     // disable for this header only

#pragma warning(disable:4512)
#pragma warning(disable:4180)
   
#include "ThirdParty/TPTrace.h"

#pragma warning(pop)      // restore original warning level   

Conclusion

So in this chapter we have learnt how to rephrase our code a bit and avoid warnings. That makes a reviewer of the code feel the code elegance and you can ensure that he correctly understands what you attempted to do in the code. After all the software business runs that way half the time. In the next chapter, let us see other practices that help us write good code.

"Always write good code. Feel bad to write bad code." - Herb Sutter.

History

         Initial Version � 14 April 2005.

         Updated � 20 April 2005 � Updated comments from readers.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here