Thinking in C++ Notes(10)

Chapter 10: Name Control

  • static has 2 meanings:
    1. allocate once at a fixed address, static storage.
    2. Local to a particular translation unit, file static.
  • DO NOT call exit() in destructor.
  • In C++, the constructor for a global static object is called before main(), destructor is executed after main().
  • external linkage: name is visible throughout all translation units in a program.(global variables and ordinary functions)
  • internal linkage: you can use the same name in other translation units without a name clash.
  • linkage refers only to elements that have addresses at a link/load time.
    class declarations and local variables have no linkage.
  • static/extern alters the storage for local variables and alters the visibility for global variables.

    int a = 0;   /* initialize a global variable. */
    extern int a;/* declare a global variable. */
    extern int a = 0; /* you will get a warning: a is initialized and declared as 'extern'. This is possibly a mistake, you should define a in a file and declare 'extern' a in other files. DO NOT do the declaration and initialization at the same time. */

  • Namespaces

    • a namespace definition can only at global scope or nested within another namespace.
    • ";" is not needed after the definition
    • a namespace definition can be "continued" over multiple header files
    • a namespace can be aliased to another name
    • you cannot create an instance of a namespace
    • "unnamed namespace" is a namespace without an identifier. names in unnamed namespace are automatically available in that translation unit without qualification. so it give you another choice to give an name internal linkage by putting it in an unnamed namespace.
    • inject friend declaration
    • names from the using directives can be overrode as if they've been declared globally to that scope.

      using namespace ns1;
      int a;   //hides ns1::a, it has the same effect if you use "using ns2::a;"

      a using declaration is a declaration within the current scope.

      using ns1::a;
      int a;   // this will cause a redeclaration

    • using declaration has no type information, so if the namespace contains a set of overloaded function with the same name, the using declaration declares all the functions in the overloaded set.
      it is possible for a using declaration to cause the overload of a function with the same argument type.

  • Static members in C++

    • the definition(initialization) of static data member must occur outside the class and only one definition is allowed
    • static consts of integral types can be defined/initialized inside class.
      static const objects of class types and array of such objects cannot be initialized using the "inline syntax".
    • a static member function has no "this", so it cannot access ordinary data members,only static data members or call other static member function.
    • make a single object of a class:
      put a static member of the same class inside the class, make the constructor private. then you can access the object but you cannot create any new object.

  • Static initialization dependency
    this problem only occurs with static object initializer that depend on each other.

    /* a.cpp */
    extern int y;
    int x=y+1;

    /* b.cpp */
    extern int x;
    int y=x+1;

    for all static objects, the linking-loading mechanism guarantees a static initialization to zero before the dynamic initialization specified by the programmer takes place.
    there is no guarantee concerning the order of initialization of static objects across translation units.
    two techniques to solve this problem.

    1. the first technique requires an additional class in your library header file.
      The class is responsible for the dynamic initialization of your library’s static objects.
      all your library’s static objects is initialized in the constructor and you can guarantee the initialization will only be preformed once by a static counter data member in the additional class.
    2. the second technique relies on the fact that static objects inside functions are initialized the first time(only) that the function is called.
      For any initialization dependency, you place a static object inside a function that returns a references to that function.
      this way, the only way you can access the static object is by calling the function, and if that object needs to access static objects on which it is dependent it must call their functions.
      and the first time a function is called, it forces the initialization to take place.

Comments