A global variable is declared in the highest-level block in which it is used.

A scope is a region of the program and broadly speaking there are three places, where variables can be declared:

  • Inside a function or a block which is called local variables,
  • In the definition of function parameters which is called formal parameters.
  • Outside of all functions which is called global variables.
  • Here let us explain what local and global variables are.

    Local Variables

    Variables that are declared inside a function or block are local variables. They can be used only by statements that are inside that function or block of code. Local variables are not known to functions outside their own. Following is the example using local variables:

    #include 
    using namespace std;
     
    int main ()
    {
      // Local variable declaration:
      int a, b;
      int c;
     
      // actual initialization
      a = 10;
      b = 20;
      c = a + b;
     
      cout << c;
     
      return 0;
    }
    
    Global Variables

    Global variables are defined outside of all the functions, usually on top of the program. The global variables will hold their type throughout the life-time of your program.

    A global variable can be accessed by any function. That is, a global variable is available for use throughout your entire program after its declaration. Following is the example using global and local variables:

    #include 
    using namespace std;
     
    // Global variable declaration:
    int g;
     
    int main ()
    {
      // Local variable declaration:
      int a, b;
     
      // actual initialization
      a = 10;
      b = 20;
      g = a + b;
     
      cout << g;
     
      return 0;
    }
    
    

    A program can have same name for local and global variables but value of local variable inside a function will take preference. For example:

    Automated analysis is the main advantage to working with a modern statically typed compiled language like C++. Code analysis tools can inform us when we have implemented an operator overload with a non-canonical form, when we should have made a method const, or when the scope of a variable can be reduced.

    In short, these tools catch the most commonly agreed best practice mistakes we are making and help educate us to write better code. We will be fully utilizing these tools.

    Compilers

    All reasonable warning levels should be enabled. Some warning levels, such as GCC's

    // this function does something
    int myFunc()
    {
    }
    6 warning mode can be too noisy and will not be recommended for normal compilation.

    GCC / Clang

    A good combination of settings is

    // this function does something
    int myFunc()
    {
    }
    7

    • // this function does something
      int myFunc()
      {
      }
      8: reasonable and standard
    • // this function does something
      int myFunc()
      {
      }
      9: warn the user if a variable declaration shadows another with the same name in the same scope
    • /*
      // this function does something
      int myFunc()
      {
      }
      */
      0: warn the user if a class with virtual functions has a non-virtual destructor. This can lead to hard to track down memory errors
    • /*
      // this function does something
      int myFunc()
      {
      }
      */
      1: warn about non-portable code, C++ that uses language extensions.

    MSVC

    MSVC has fewer warning options, so all warnings should be enabled:

    /*
    // this function does something
    int myFunc()
    {
    }
    */
    2.
    /*
    // this function does something
    int myFunc()
    {
    }
    */
    3 could be considered, but does not seem to be recommended even by microsoft.

    Static Analyzers

    Static analyzers look for errors that compilers do not look for, such as potential performance and memory issues.

    Cppcheck

    Cppcheck is free and opensource. It strives for 0 false positives and does a good job at it. Therefor all warning should be enabled:

    /*
    // this function does something
    int myFunc()
    {
    }
    */
    4

    Clang's Static Analyzer

    Clang's analyzer's default options are good for the respective platform. It can be used directly from cmake.

    MSVC's Static Analyzer

    Can be enabled with the

    /*
    // this function does something
    int myFunc()
    {
    }
    */
    5 command line option. For now we will stick with the default options.

    Code Coverage Analysis

    A coverage analysis tool shall be run when tests are executed to make sure the entire application is being tested. Unfortunately, coverage analysis requires that compiler optimizations be disabled. This can result in significantly longer test execution times.

    The most likely candidate for a coverage visualization is the lcov project. A secondary option is coveralls, which is free for open source projects.

    Ignoring Warnings

    If it is determined by team consensus that the compiler or analyzer is warning on something that is either incorrect or unavoidable, the team will disable the specific error to as localized part of the code as possible.

    Unit Tests

    There should be a test enabled for every feature or bug fix that is committed. See also "Code Coverage Analysis."

    THIS DOCUMENTIS OUT OFDATESee https://github.com/lefticus/cppbestpractices/blob/master/00-Table_of_Contents.md Instead!C++ Coding Standards Part 1: Style

    Style guidelines are not overly strict. The important thing is that code is clear and readable with an appropriate amount of whitespace and reasonable length lines. A few best practices are also mentioned.

    Descriptive and Consistent Naming

    C++ allows for arbitrary length identifier names, so there's no reason to be terse when naming variables. Use descriptive names, and be consistent in the style

    • /*
      // this function does something
      int myFunc()
      {
      }
      */
      6
    • /*
      // this function does something
      int myFunc()
      {
      }
      */
      7

    are common examples. snake_case has the advantage that it can also work with spell checkers, if desired.

    Common C++ Naming Conventions

    • Types start with capitals:
      /*
      // this function does something
      int myFunc()
      {
      }
      */
      8
    • functions and variables start with lower case:
      /*
      // this function does something
      int myFunc()
      {
      }
      */
      9
    • constants are all capital:
      #ifndef MYPROJECT_MYCLASS_HPP
      #define MYPROEJCT_MYCLASS_HPP
      
      namespace MyProject {
      class MyClass {
      };
      }
      
      #endif
      0

    Note that the C++ standard does not follow any of these guidelines. Everything in the standard is lowercase only.

    Distinguish Private Object Data

    Name private data with a

    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    1 prefix to distinguish it from public data.

    Distinguish Function Parameters

    Name function parameters with an

    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    2 prefix.

    Well formed example

    class MyClass
    {
    public:
      MyClass(int t_data)
        : m_data(t_data)
      {
      }
      
      int getData() const
      {
        return m_data;
      }
      
    private:
      int m_data;
    };

    Distinguish C++ Files From C Files

    C++ source file should be named

    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    3 or
    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    4 NOT
    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    5 C++ header files should be named
    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    6 NOT
    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    7

    Use #ifndef MYPROJECT_MYCLASS_HPP #define MYPROEJCT_MYCLASS_HPP namespace MyProject { class MyClass { }; } #endif8

    C++11 introduces

    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif
    8 which is a special type denoting a null pointer value. This should be used instead of 0 or NULL to indicate a null pointer.

    Comments

    Comment blocks should use

    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    0, not
    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    1. Using
    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    0 makes it much easier to comment out a block of code while debugging.

    // this function does something
    int myFunc()
    {
    }

    To comment out this function block during debugging we might do:

    /*
    // this function does something
    int myFunc()
    {
    }
    */

    which would be impossible if the function comment header used

    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    1

    Never Use // Good Idea int myFunction(bool t_b) { if (t_b) { // do something } }4 In a Header File

    This causes the name space you are

    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    4 to be pulled into the namespace of the header file.

    Include Guards

    Header files must contain an distinctly named include guard to avoid problems with including the same header multiple times or conflicting with other headers from other projects

    #ifndef MYPROJECT_MYCLASS_HPP
    #define MYPROEJCT_MYCLASS_HPP
    
    namespace MyProject {
    class MyClass {
    };
    }
    
    #endif

    2 spaces indent level.

    Tabs are not allowed, and a mixture of tabs and spaces is strictly forbidden. Modern autoindenting IDEs and editors require a consistent standard to be set.

    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }

    {} are required for blocks.

    Leaving them off can lead to semantic errors in the code.

    // Bad Idea
    // this compiles and does what you want, but can lead to confusing
    // errors if close attention is not paid.
    for (int i = 0; i < 15; ++i)
      std::cout << i << std::endl;
    
    // Bad Idea
    // the cout is not part of the loop in this case even though it appears to be
    int sum = 0;
    for (int i = 0; i < 15; ++i)
      ++sum;
      std::cout << i << std::endl;
      
      
    // Good Idea
    // It's clear which statements are part of the loop (or if block, or whatever)
    int sum = 0;
    for (int i = 0; i < 15; ++i) {
      ++sum;
      std::cout << i << std::endl;
    }

    Keep lines a reasonable length

    // Bad Idea
    // hard to follow
    if (x && y && myFunctionThatReturnsBool() && caseNumber3 && (15 > 12 || 2 < 3)) { 
    }
    
    // Good Idea
    // Logical grouping, easier to read
    if (x && y && myFunctionThatReturnsBool() 
        && caseNumber3 
        && (15 > 12 || 2 < 3)) { 
    }

    Use "" For Including Local Files

    ...

    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    6 is reserved for system includes.

    // Bad Idea. Requires extra -I directives to the compiler
    // and goes against standards
    #include <string>
    #include <includes/MyHeader.hpp>
    
    // Worse Idea
    // requires potentially even more specific -I directives and 
    // makes code more difficult to package and distribute
    #include <string>
    #include <MyHeader.hpp>
    
    
    // Good Idea
    // requires no extra params and notifies the user that the file
    // is a local file
    #include <string>
    #include "MyHeader.hpp"

    Initialize Member Variables

    ...with the member initializer list

    // Bad Idea
    class MyClass
    {
    public:
      MyClass(int t_value)
      {
        m_value = t_value;
      }
    
    private:
      int m_value;
    };
    
    
    // Good Idea
    // C++'s memeber initializer list is unique to the language and leads to
    // cleaner code and potential performance gains that other languages cannot 
    // match
    class MyClass
    {
    public:
      MyClass(int t_value)
        : m_value(t_value)
      {
      }
    
    private:
      int m_value;
    };

    Forward Declare when Possible

    This:

    // some header file
    class MyClass;
    
    void doSomething(const MyClass &);

    instead of:

    // this function does something
    int myFunc()
    {
    }
    0

    This is a proactive approach to simplify compilation time and rebuilding dependencies.

    Always Use Namespaces

    There is almost never a reason to declare an identifier in the global namespaces. Instead, functions and classes should exist in an appropriately named namespaces or in a class inside of a namespace. Identifiers which are placed in the global namespace risk conflicting with identifiers from other (mostly C, which doesn't have namespaces) libraries.

    Avoid Compiler Macros

    Compiler definitions and macros are replaced by the pre-processor before the compiler is ever run. This can make debugging very difficult because the debugger doesn't know where the source came from.

    // this function does something
    int myFunc()
    {
    }
    1

    THIS DOCUMENTIS OUT OFDATESee https://github.com/lefticus/cppbestpractices/blob/master/00-Table_of_Contents.md Instead!C++ Coding Standards Part 2: Performance and Safety

    Limit Variable Scope

    Variables should be declared as late as possible, and ideally, only when it's possible to initialize the object. Reduced variable scope results in less memory being used, more efficient code in general, and helps the compiler optimize the code further.

    // this function does something
    int myFunc()
    {
    }
    2

    Use Exceptions Instead of Return Values to Indicate Error

    Exceptions cannot be ignored. Return values, such as using

    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    7, can be ignored and if not checked can cause crashes or memory errors. An exception, on the other hand, can be caught and handled. Potentially all the way up the highest level of the application with a log and automatic restart of the application.

    Stroustrup, the original designer of C++, much better than I ever could.

    Avoid raw memory access

    Raw memory access, allocation and deallocation, are difficult to get correct in C++ without risking memory errors and leaks. C++11 provides tools to avoid these problems.

    // this function does something
    int myFunc()
    {
    }
    3

    Avoid global data

    ... this includes singleton objects

    Global data leads to unintended sideeffects between functions and can make code difficult or impossible to parallelize. Even if the code is not intended today for parallelization, there is no reason to make it impossible for the future.

    Prefer pre-increment to post-increment

    ... when it is semantically correct. Pre-increment is faster then post-increment because it does not require a copy of the object to be made.

    // this function does something
    int myFunc()
    {
    }
    4

    Const as much as possible

    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    8 tells the compiler that a variable or method is immutable. This helps the compiler optimize the code and helps the developer know if a function side effects. Also, using
    // Good Idea
    int myFunction(bool t_b)
    {
      if (t_b)
      {
        // do something
      }
    }
    9 prevents the compiler from copying data unnecessarily. Here are some comments on const from John Carmack.

    // this function does something
    int myFunc()
    {
    }
    5

    Prefer Stack Operations to Heap Operations

    Heap operations have performance penalties in mulithreaded environments on most platforms and can possibly lead to memory errors if not used carefully.

    Modern C++11 has special move operations which are designed to enhances the performance of stack based data by reducing or eliminating copies, which can bring even the single threaded case on par with heap based operations.

    Where should global variables be declared?

    Hence, the natural place to put global variable declaration statements is before any function definitions: i.e., right at the beginning of the program. Global variables declarations can be used to initialize such variables, in the regular manner.

    When can global variables be used?

    Global variables should be used when multiple functions need to access the data or write to an object. For example, if you had to pass data or a reference to multiple functions such as a single log file, a connection pool, or a hardware reference that needs to be accessed across the application.

    Are global variables declared in main?

    A global variable is a variable defined in the 'main' program. Such variables are said to have 'global' scope. A local variable is a variable defined within a function. Such variables are said to have local 'scope'.

    What are global variables How are these variable declared?

    Global Variables are the variables that can be accessed from anywhere in the program. These are the variables that are declared in the main body of the source code and outside all the functions. These variables are available to every function to access. Var keyword is used to declare variables globally.