Click here to Skip to main content
11,435,319 members (48,782 online)
Click here to Skip to main content
Technical Blog

Tagged as

using / namespace

, 18 May 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
using and namespace are two of the most useful C++ keywords when it comes to simplifying syntax, and clarifying your intentions with the code. You should understand the value and flexibility these constructs will add to your software and it maintenance. The benefits are realized in the form of orga

using and namespace are two of the most useful C++ keywords when it comes to simplifying syntax, and clarifying your intentions with the code. You should understand the value and flexibility these constructs will add to your software and it maintenance. The benefits are realized in the form of organization, readability, and adaptability of your code. Integration with 3rd party libraries, code from different teams, and even the ability to simplify names of constructs in your programs are all situations where these two keywords will help. Beware, these keywords can also cause unnecessary pain when used incorrectly. There are some very simple rules to keep in mind, and you can avoid these headaches.

The Compiler and Linker

At its core, The Compiler, is an automaton that works to translate our code that is mostly human readable, a form understood by your target platform. These programs are works of art in and of themselves. They have become very complex to address our complex needs in both our languages and the advances in computing in the last few decades. For C/C++, the compiled module is not capable of running on the computer yet, the linker needs to get involved.

The compiler create a separate compiled module for each source file (.c, .cpp, .cc) that is in your program. Each compiled module contains a set of symbols that are used to reference the code and data in your program. The symbols created in these modules will be one of three different types:

  1. Internal Symbol: An element that is completely defined and used internally in the module.
  2. Exported. Symbol: An element this is defined internally to this module, and advertised as accessible for other modules.
  3. Imported Symbol: An element that is used within a module, however the definition is contained with another module. This is indicated with the extern qualifier.

Now it's time for The Linker to take each individual module and link them together; similar to stitching together the individual patches in a quilt. The Linker combines all of the individual modules, resolving any dependencies that were indicated by The Compiler. If a module is expecting to import a symbol, the linker will attempt to find that symbol in the other set of modules.

If all works out well, every module that is expecting to import a symbol will now have location to reference that symbol. If a symbol cannot be found, you will receive a linker error indicating "Missing Symbol". Alternatively, if a symbol is defined in multiple modules The Linker will not be able to determine which symbol is the correct symbol to associate with the import module. The Linker will issue a "Duplicate Symbol" error.

Namespaces

The duplicate symbol linker error can occur for many reasons, such as:

  • A function is implemented in a header file without the inline keyword.
  • A global variable or function with the same name is found in two separate source code modules.
  • Adding a 3rd party library that defines a symbol in one of its modules that match a symbol in your code.

The first two items on the list are relatively easy to fix. Simply change the name of your variable or function. Generally a convention is adopted, and all of the names of functions and variables end up with a prefix that specifies the module. Something similar to this:

C/C++

// HelpDialog.cpp
int g_helpDialogId;
int g_helpTopic;
int g_helpSubTopic;
int HelpCreateDialog()
{
// ...
}

This solution works. However, it's cumbersome, won't solve the issue of a 3rd party library that creates the same symbol and finally, it's simply unnecessary in C++. Place these declarations in a namespace. This will give the code a context that will help make your symbols unique:

C/C++

// HelpDialog.cpp
namespace help
{
int g_dialogId;
int g_topic;
int g_subTopic;
 
int CreateDialog()
{
// ...
}
} // namespace help

The symbols in the code above no longer exist in the globally scoped namespace. To access the symbols, the name must be qualified with help::, similarly to referencing a static symbol in a class definition. Yes, it is still entirely possible for a 3rd party library to use the same namespace. Namespaces can be nested. Therefore to avoid a symbol collision such as this, place the help namespace into a namespace specified for your library or application:

C/C++

namespace netlib
{
namespace help
{
 
// ... Symbols, Code, 
} // namespace help
} // namespace netlib

Namespaces Are Open

Unlike a class definition, a namespace's declaration is open. This means that multiple blocks can be defined for a namespace and the combined set of declarations will live in a single namespace. Multiple blocks can appear in the same file and separate blocks can be in multiple files. It is possible for a namespace block to spread across two library modules, however, the separate libraries would need to be compiled by compiler that uses the same name-mangling algorithm. For those that are unaware, name-mangling is the term used to describe the adornments the C++ compiler gives to a symbol to support a feature such as function overloading.

C/C++

namespace code
{
namespace detail
{
// Forward declare support functions symbols
int VerifySyntax(const string &path);
} 
// Main implementation
namespace detail
{
// New symbols can be defined and added
bool has_error = false;
// Implement functions
int VerifySyntax(const string &path)
{
// ...
}
} // namespace detail
} // namespace code

The Unnamed Namespace

The static keyword is used In C to declare a global variable or a function, and limit its scope to the current source file. This method is also supported in C++ for backward compatibility. However, there is a better way hide access to globally scoped symbols; use the unnamed namespace. This is simply a defined namespace that is given a unique name, only accessible to the compiler. To reference symbols in this namespace, access it as if it lived in the global namespace. Each module is given their own unnamed namespace. Therefore it is not possible to access unnamed namespace symbols defined in a different module.

C/C++

namespace // unnamed
{
int g_count;
} // namespace (unnamed)
 
// Access a variable in the unnamed namespace
// as if it were defined in the globally scoped namespace
int GetCount()
{
return g_count;
}
 
} // namespace (unnamed)

The code above is an example for how to protect access to global variables. If you desire a different source module to be able to access the variable, create a function for other modules to call to gain access to the global variable. This helps keep control of how the variable is used, and control how the value of the variable is changed.

Alias a Namespace

Namespaces share the same rules defined for naming functions and variables. Potentially long namespace names could be created to properly/uniquely describe a set of code. For example:

C/C++

namespace CodeOfTheDamned
{
namespace network
{
enum Interface
{
k_type1 = 1,
k_type2,
k_type3 
}
class Buffer
{
// ...
}
} // namespace network
} // namespace CodeOfTheDamned

The fully scoped names that these definitions create could become quite cumbersome to deal with.

C/C++

CodeOfTheDamned::network::Interface intf = CodeOfTheDamned::network::k_type1;
If (CodeOfTheDamned::network::k_type1 == intf)
{
CodeOfTheDamned::network::Buffer buffer;
// ...
}

Compare and contrast this with the code that did not use namespaces:

C/C++

Interface intf = k_type1;
If (k_type1 == intf)
{
Buffer buffer;
// ...
}

Possibly the top item on my list for creating maintainable software is to make using existing declarations easy to understand and use. Typing a long cumbersome prefix is not easy. I like to keep my namespace names between 2 to 4 characters long. Even still the effort required to specify a fully qualified path becomes painful again once you hit the second nested namespace; 3 namespaces or more is just sadistic. Enter, the namespace alias. This syntax allows you to redeclare an existing namespace with an alias that may be simpler to use. For Example:

C/C++

// Namespace Alias Syntax
namespace cod  = CodeOfTheDamned;
namespace dnet = cod::network;
 
// Example of new usage
If (dnet::k_type1 == intf)
{
dnet::Buffer buffer;
// ...
}

This is much nicer, simple, convenient. We can do better though. There is one other keyword in C++ that helps simplify the usage of namespaces when organizing your code, using .

Using

using allows a name that is defined in a different declarative region to be defined in the same declarative region, which using appears. More simply stated, using adds a definition from some other namespace to the same namespace using is declared.

C/C++

// Syntax for using
// Bring a single item into this namespace
using std::cout;
using CodeOfTheDamned::network::Buffer;
 
// Now these symbols are in this namespace as well as their original namespace:
cout &lt;< "Hello World";
Buffer buffer;

Using with Namespaces

The ability to bring a symbol far far away from another namespace is greatly simplified with using . using can also bring the contents of an entire namespace into the current declarative region. However, this particular usage should be used sparingly because to avoid defeating the purpose of namespaces. The contents of two namespaces are combined together. One absolute rule that I would recommend for your code guidelines, is to prohibit the use of using in header files to bring namespaces into the global namespace.

C/C++

// Syntax for using
// Bring a single item into this namespace
using namespace std;
using namespace CodeOfTheDamned;
 
// The entire std namespace has been brought into this scope
cout &lt;< "Hello World" &lt;< endl ;
 
// The CodeOfTheDamned namespace was brought to us.
// However, qualifying with the network sub-namespace
// will still be required.
network::Buffer buffer;
</code></ endl>

lock

My preferred use of using is inside of a function block. A few simple declarations at the top of the function allows me to quickly see which symbols I am pulling in to use within the function, and I simplify the code at the same time. Only the specific symbols I intend to use are brought into the scope of the function. I limit what is imported, to the set of symbols that are actually used.:

C/C++

// using within a function definition
// Forward declaration
void Process(int number);
 
void ProcessList(NumberList &amp;numbers)
{
using std::for_each;
// Preparations ...
for_each(numbers.begin(),
numbers.end(),
Process);
// ...
}

using Within a Class

using can be used within a class declaration. Unfortunately it cannot be used to bring namespace definitions into the class scope. using is used within a class scope to bring definitions from a base class into the scope of a derived class without requiring explicit qualification. Another feature to note, is the accessibility of a declaration can be modified in a base class with using.

I have found this most useful creating classes built upon templates. When creating generic programs it is helpful to remove as many of the explicit definitions as possible and depend on the well defined lookup rules of the compiler to determine the most appropriate type. Unfortunately, I do not have any full examples to demonstrate the context where I have actually needed this feature. The next time I run across one I will try to remember to update this example. For now, here is the general concept.

C/C++

// Syntax for using
// Bring a symbol from a base class into this class scope.
class Base
{
public:
int value;
// ...
};
 
class Derived
: private Base
{
public:
// Base::value will continue to be accessible
// in the public interface, even though all
// of the Base classes constructs are hidden.
using Base::value;
 
};

Conclusion

using and namespace are two very useful declarations to be aware of in C++ to help create a balance between portability, adaptability and ease of coding. The ability to define namespaces allows code symbols from separate libraries to be segregated to prevent name collisions when using libraries developed by multiple development teams. The keyword using allows the developer to bring specific elements from a namespace into the current declarative scope for convenience.

A little care must be taken to ensure that over-zealous use of the using keyword does not undermine any organizational structure created with namespace. However, with the introduction of a few conventions to your coding standards, the effort required to properly organize your code into logical units that avoid name collisions can be kept to a minimum. The importance that you invest in a namespace structure increases with likelihood that your code is to be ported across multiple platforms, to use 3rd party libraries, or to be sold as a library. I believe the results are well worth little effort required.

Original post blogged at Code of the Damned.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Paul M Watt
Architect L3 Communications
United States United States
I am a software architect and I have been developing software for nearly two decades. Over the years I have learned to value maintainable solutions first. This has allowed me to adapt my projects to meet the challenges that inevitably appear during development. I use the most beneficial short-term achievements to drive the software I develop towards a long-term vision.

C++ is my strongest language. However, I have also used x86 ASM, ARM ASM, C, C#, JAVA, Python, and JavaScript to solve programming problems. I have worked in a variety of industries throughout my career, which include:
• Manufacturing
• Consumer Products
• Virtualization
• Computer Infrastructure Management
• DoD Contracting

My experience spans these hardware types and operating systems:
• Desktop
o Windows (Full-stack: GUI, Application, Service, Kernel Driver)
o Linux (Application, Daemon)
• Mobile Devices
o Windows CE / Windows Phone
o Linux
• Embedded Devices
o VxWorks (RTOS)
o Greenhills Linux
o Embedded Windows XP

I am a Mentor and frequent contributor to CodeProject.com with tutorial articles that teach others about the inner workings of the Windows APIs.

I am the creator of an open source project on GitHub called Alchemy[^], which is an open-source compile-time data serialization library.

I maintain my own repository and blog at CodeOfTheDamned.com/[^], because code maintenance does not have to be a living hell.
Follow on   Twitter   LinkedIn

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150428.2 | Last Updated 18 May 2014
Article Copyright 2014 by Paul M Watt
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid