Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
Page Tree | ||||
---|---|---|---|---|
|
6. Miscellaneous
6.
1Templates1 Templates
Templates are in one respect very similar to an inline function. No code is generated when the compiler sees the declaration of a template; code is generated only when a template instantiation is needed.
A function template instantiation is needed when the template is called or its address is referenced and a class template instantiation is needed when an object of the template instantiation class is declared.
The template specifier for a template class should be placed alone on the line preceding the "class" keyword or the return type for a function. Template parameters should be in upper case.
// template declaration template<class T> class ListTemplate { public: T front(); ... }; // template definition template<class T> T ListTemplate<T>::front() { ...; }
A big problem is that there is no standard for how code that uses templates is compiled. The compilers that require the complete template definition to be visible usually instantiate the template whenever it is needed and then use a flexible linker to remove redundant instantiations of the template member function. However, this solution is not possible on all systems; the linkers on most UNIX-systems cannot do this.
Even though there is a standard for how templates themselves should be compiled, there are still many compilers that do not follow the standard. Some compilers require the complete template definition to be visible, even though that is not required by the standard.
This means that we have a potential portability problem when writing code that uses templates.
=>We recommend that you put the implementation of template functions in a separate file, a template definition file, and use conditional compilation to control whether that file is included by the header file. A macro is either set or not depending on what compiler you use. An inconvenience is that you now have to manage more files. Only inclusion of the header file should be needed.
#ifndef QueueTemplate_hpp #define QueueTemplate_hpp
template <class T> class QueueTemplate { public: QueueTemplate(); // ... void insert(const T &t); };
//--------------------------------- // Template Definition //--------------------------------- #ifndef EXTERNAL_TEMPLATE_DEFINITION #include "QueueTemplate.cpp" #endif
#endif
6.2Program Files
- Files should all begin with a file prolog (see below).
- Organize a program into two types of files as follows:
Header File (.hpp) - should contain:
-A class declaration -Any global type declarations -Any exceptions -Any typedefs
- Any includes for template files -ENUM type definitions
Source File (.cpp) - should contain:
-Any Static and/or Constant data values -Method definitions (implementation)
- Organize header files by class (one class declaration per header file) or by logical grouping of functions (e.g. RealUtilities)
- The main procedure should reside in its own file.
- For source files which contain related functions (utilities, for example), follow guidelines for putting functions in some meaningful order.
- Do not use rows of asterisks to separate functions.
- There should be only one class or namespace per .hpp/.cpp pair. There may be exceptions to this, though, if a set of namespaces or classes are small and may be logically grouped together.
6.3Portability
- Use ANSI/ISO C++ whenever it is available.
- When optimizing, some thought must be given to portability issues.
- Consider optimizations right from the start, as it is much harder to go back and redesign or recode later.
- Pass "large" arguments (instances of classes or structs) to a function by const reference when the arguments don't need to be modified and pass as reference when they need to be modified
- Place typedefs for all common types (e.g. Real defined as double, Integer defined as int) in a central header file, accessible by all code, for easier portability to other platforms and to higher precision types.
6.4Efficiency
- For efficiency, minimize the number of constructor/destructor calls: this means minimize the number of local objects that are constructed; construct on returning from a method, rather than creating a local object, assigning to it, and then returning it; pass large objects by const reference; etc.
- For efficiency, use exceptions only for truly exceptional conditions, not for message passing
- Use embedded assignments when they are proven to be more efficient than not using them.
while ((c = getchar()) != EOF) { ... }
6.5Extern statements / External variables
- Avoid using extern statements in the header file. Whenever possible, the source files referencing the global data should "extern" the needed global data, so that reader will know which variables are declared external to that source file.
- Avoid declaring non-static external variables. Variables needed by more than one file should appear in a .cpp file and be externed in a source file.
6.6Preprocessor Directives
- Include a preprocessor directive in the main header file, accessed by all code, e.g.
#ifndef GMAT_API #define GMAT_API #endif
6.7Mixing C and C++
- Include files which contain code that is accepted by both C and C++ compilers should have the file name extension ".h".
- Make the header files work correctly when they are included by both C and C++ files. If you start including an existing C header in new C++ files, fix the C header file to support C++ (as well as C), don't just extern "C" { } the C header file.
In C header file:
#ifdef __cplusplus extern "C" { #endif int existingCfunction1(…); int existingCfunction2(…); #ifdef __cplusplus } #endif
6.8 SVN Keywords
- If SVN is used for configuration management, the top of every file should contain the following lines (or those agreed upon by the project/team):
//$Id$
- The command to replace the keyword with actual data is:
svn propset svn:keywords Id filename
6.9README file
- A README file should be used to explain what the program does and how it is organized and to document issues for the program as a whole. For example, a README file might include:
-All conditional compilation flags and their meanings. -Files that are machine dependent -Paths to reused components -History information about the current and previous releases -Information about existing major bugs and fixes -A brief description of new features added to the system
6.10 Makefiles
- Makefiles are used on some systems to provide a mechanism for efficiently recompiling C++ code. With makefiles, the make utility recompiles files that have been changed since the last compilation. Makefiles also allow the recompilation commands to be stored, so that potentially long CC commands can be greatly abbreviated.
The makefile
-Lists all files that are to be included as part of the program. -Contains comments documenting what files are part of libraries. -Demonstrates dependencies, e.g., source files and associated headers using implicit and explicit rules.
6.11Standard Libraries
- A standard library is a collection of commonly used functions combined into one file. Examples of function libraries include <iostream> which comprises a group of input/output functions and <math> which consists of mathematical functions. When using library files, include only those libraries that contain functions that your program needs. You may create your own libraries of routines and group them in header files.
- Use C++ standard libraries, instead of C libraries, whenever possible, unless it is more efficient to use C libraries.
6.12Use of Namespaces
The use of namespaces minimizes potential name clashes in C++ programs and libraries and eliminates the use of global types, variables, etc.
Clashable names include: external variable names, external function names, top-level class names, type names in public header files, class member names in public header files, etc. (Class member names are scoped by the class, but can clash in the scope of a derived class. Explicit scoping can be used to resolve these clashes.)
It is no longer necessary to have global types, variables, constants and functions if namespaces are used. Names inside namespaces are as easy to use as global names, except that you sometimes must use the scope operator. Without namespaces it is common to add a common identifier as a prefix to the name of each class in a set of related classes.
It is recommended not to place using <namespace> directives at global scope in a header file; instead place it in a source file. This can cause lots of magic invisible conflicts that are hard to track since it will make names globally accessible to all files that include that header, which is what we are trying to avoid. Inside an implementation file, using directives are less dangerous and sometimes very convenient. On the other hand, too-frequent use of the scope operator is not recommended. The difference between local names and other names will be more explicit, but more code needs be rewritten if the namespaces are reorganized.
6.13Standard Template Library (STL)
- Use Standard Template Library components, when available.
6.14Using the new Operator
- The specification for operator "new" was changed by the standardization committee, so that it throws an exception of type std::bad_alloc when it fails. Therefore, the code may catch this exception, rather than check for a NULL value. e.g.
#include <stdexcept>
int someFunction() { try { SomeClass *someClassList = new SomeClass[size]; } catch (std::bad_alloc &ex) { … } }
Anchor | ||||
---|---|---|---|---|
|
A.1Example of a header file.
//$Id:$ //------------------------------------------------------------------------------ // EopFile //------------------------------------------------------------------------------ // GMAT: General Mission Analysis Tool. // // Copyright (c) 2002-2011 United States Government as represented by the // Administrator of The National Aeronautics and Space Administration. // All Other Rights Reserved. // // Developed jointly by NASA/GSFC and Thinking Systems, Inc. under // MOMS Task order 124. // // Author: Wendy C. Shoan/GSFC/MAB // Created: 2005/01/26 // /**
- Definition of the EopFile class. This is the code that reads the polar*
- motion information, as well as the UT1-UTC offset, from EOP file.* *** */ //------------------------------------------------------------------------------
#ifndef EopFile_hpp #define EopFile_hpp
#include "gmatdefs.hpp" #include "Rmatrix.hpp"
namespace GmatEop { enum EopFileType { EOP_C04, FINALS }; };
class GMAT_API EopFile { public: // default constructor EopFile(const std::string &fileName = "eopc04.62-now", GmatEop::EopFileType eop = GmatEop::EOP_C04); // copy constructor EopFile(const EopFile &eopF); // operator = const EopFile& operator=(const EopFile &eopF); // destructor virtual ~EopFile();
// initializes the EopFile (reads it and stores the data) virtual void Initialize();
// method to return the name of the EOP file virtual std::string GetFileName() const;
// method to return the UT1-UTC offset for the given UTCMjd virtual Real GetUt1UtcOffset(const Real utcMjd);
// method to return JD, X, Y, LOD data (for use by coordinate systems) virtual Rmatrix GetPolarMotionData(); // interpolate x, y, and lod to input time virtual bool GetPolarMotionAndLod(Real forUtcMjd, Real &xval, Real &yval, Real &lodval);
protected:
static const Integer MAX_TABLE_SIZE;
GmatEop::EopFileType eopFType; std::string eopFileName; Integer tableSz;
/// table of polar motion data : MJD, X, Y, LOD Rmatrix polarMotion;* /// vector of UT1-UTC offsets : MJD, offset Rmatrix ut1UtcOffsets;*
Real lastUtcJd; Real lastOffset; Integer lastIndex;
bool isInitialized;
bool IsBlank(const char aLine);*
// Performance code Integer previousIndex;
}; #endif // EopFile_hpp A.2 Example of a source file.
//$Id:$ //------------------------------------------------------------------------------ // EopFile //------------------------------------------------------------------------------ // GMAT: General Mission Analysis Tool. // // Copyright (c) 2002-2011 United States Government as represented by the // Administrator of The National Aeronautics and Space Administration. // All Other Rights Reserved. // // Developed jointly by NASA/GSFC and Thinking Systems, Inc. under // MOMS Task order 124. // // Author: Wendy C. Shoan // Created: 2005/01/26 // /** - Implementation of the EopFile class. This is the code that reads the polar*
- motion information from EOP file.* *** */ //------------------------------------------------------------------------------
#include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include "gmatdefs.hpp" #include "EopFile.hpp" #include "TimeTypes.hpp" #include "UtilityException.hpp" #include "RealUtilities.hpp" #include "MessageInterface.hpp"
//#define DEBUG_OFFSET //#define DEBUG_EOP_READ //#define DEBUG_EOP_INITIALIZE
//------------------------------------------------------------------------------ // static data //------------------------------------------------------------------------------ const Integer EopFile::MAX_TABLE_SIZE = 50405; // up to year >= 2100
//------------------------------------------------------------------------------ // public methods //------------------------------------------------------------------------------
//--------------------------------------------------------------------------- // EopFile(const std::string &fileName, // GmatEop::EopFileType eop = GmatEop::EOP_C04); //--------------------------------------------------------------------------- /** - Constructs base EopFile structures used in derived classes*
- (default constructor).* ***
- @param* fileNme EOP file name. */ //--------------------------------------------------------------------------- EopFile::EopFile(const std::string &fileName, GmatEop::EopFileType eop) : eopFType (eop), eopFileName (fileName), tableSz (0), polarMotion (new Rmatrix(MAX_TABLE_SIZE,4)), ut1UtcOffsets (new Rmatrix(MAX_TABLE_SIZE,2)), lastUtcJd (0.0), lastOffset (0.0), lastIndex (0), isInitialized (false) { }
//--------------------------------------------------------------------------- // EopFile(const EopFile &eopF); //--------------------------------------------------------------------------- /** - Constructs base EopFile structures, by copying*
- the input instance (copy constructor).* ***
- @param* eopF EopFile instance to copy to create "this"
- instance.* */ //--------------------------------------------------------------------------- EopFile::EopFile(const EopFile &eopF) : eopFType (eopF.eopFType), eopFileName (eopF.eopFileName), tableSz (eopF.tableSz), polarMotion (new Rmatrix((eopF.polarMotion))),* ut1UtcOffsets (new Rmatrix((eopF.ut1UtcOffsets))),* lastUtcJd (eopF.lastUtcJd), lastOffset (eopF.lastOffset), lastIndex (eopF.lastIndex), isInitialized (eopF.isInitialized) { }
//--------------------------------------------------------------------------- // EopFile& operator=(const EopFile &eopF) //--------------------------------------------------------------------------- /** - Assignment operator for EopFile structures.* ***
- @param* eopF The original that is being copied. ***
- @return Reference to this object* */ //--------------------------------------------------------------------------- const EopFile& EopFile::operator=(const EopFile &eopF) { if (&eopF == this) return *this; eopFType = eopF.eopFType; eopFileName = eopF.eopFileName; tableSz = eopF.tableSz; delete polarMotion; delete ut1UtcOffsets; polarMotion = new Rmatrix((eopF.polarMotion));* ut1UtcOffsets = new Rmatrix((eopF.ut1UtcOffsets));* lastUtcJd = eopF.lastUtcJd; lastOffset = eopF.lastOffset; lastIndex = eopF.lastIndex; isInitialized = eopF.isInitialized; return *this; }
//--------------------------------------------------------------------------- // ~EopFile() //--------------------------------------------------------------------------- /** - Destructor.* */ //--------------------------------------------------------------------------- EopFile::~EopFile() { delete polarMotion; delete ut1UtcOffsets; }
//------------------------------------------------------------------------------ // void Initialize() //------------------------------------------------------------------------------ /** - This method initializes the EopFile class, by reading the file and*
- storing the UT1-UTC offset and polar motion data.* *** */ //------------------------------------------------------------------------------ void EopFile::Initialize() { #ifdef DEBUG_EOP_INITIALIZE MessageInterface::ShowMessage("Initializing EopFile: eopFileName = %s\n", eopFileName.c_str()); #endif if (isInitialized) return;
… … (implementation details go here) …
isInitialized = true; }
//--------------------------------------------------------------------------- // std::string GetFileName() const //--------------------------------------------------------------------------- /** - Returns the name of the EOP file.* ***
- @return name of the EOP file.* */ //--------------------------------------------------------------------------- std::string EopFile::GetFileName() const { return eopFileName; }
//--------------------------------------------------------------------------- // Real GetUt1UtcOffset(const Real utcMjd) //--------------------------------------------------------------------------- /** - Returns the UT1-UTC offset for the given utc* mjd. ***
- @param* utcMjd The utc mjd for which to return the offset. ***
- @return UT1-UTC offset for the given time; values between table entries*
- are interpolated linearly.* */ //--------------------------------------------------------------------------- Real EopFile::GetUt1UtcOffset(const Real utcMjd) { if (!isInitialized) Initialize();
if (lastUtcJd == (utcMjd + GmatTimeConstants::JD_NOV_17_1858)) return lastOffset;
… … (implementation details go here) …
return off; }
//--------------------------------------------------------------------------- // Rmatrix GetPolarMotionData() //--------------------------------------------------------------------------- /** - Returns the polar motion data.*
- for each row: mjd, x, y* ***
- @return polar motion data.* */ //--------------------------------------------------------------------------- Rmatrix EopFile::GetPolarMotionData() { return Rmatrix(*polarMotion); }
//--------------------------------------------------------------------------- // bool GetPolarMotionAndLod(Real forUtcMjd, Real &xval, Real &yval, // Real &lodval) //--------------------------------------------------------------------------- /** - Returns the polar motion data X, Y, and LOD, for the input UTC MJD time.*
- @param* forUtcMjd time for which to return the data
- @param* xval return X value of polar motion data (arcsec)
- @param* yval return Y value of polar motion data (arcsec)
- @param* lodval return LOD value (seconds) ***
- @return true, for successful computation; false otherwise* */ //--------------------------------------------------------------------------- bool EopFile::GetPolarMotionAndLod(Real forUtcMjd, Real &xval, Real &yval, Real &lodval) { if (!isInitialized) Initialize();
… … (implementation details go here) …
return true; }
//------------------------------------------------------------------------------ // bool IsBlank(char aLine)* //------------------------------------------------------------------------------ /** - This method returns true if the string is empty or is all white space.* ***
- @return flag indicating whether or not the input string is blank* */ //------------------------------------------------------------------------------ bool EopFile::IsBlank(const char aLine)* { Integer i; for (i=0;i<(int)strlen(aLine);i++) { //loj: 5/18/04 if (!isblank(aLine[i])) return false; if (!isspace(aLine[i])) return false; } return true; }
Appendix B Doxygen CommandsAnchor Doxygen_Commands Doxygen_Commands
- Below is a list of widely used commands with a description of their arguments. For a full list of all commands, refer to the Doxygen Documentation Section 21 Special Commands from http://www.stack.nl/~dimitri/doxygen/download.html#latestman.
- @author {list of authors} Starts a paragraph where one or more author names may be entered.
- @class <name> [<header-file>] [<header-name>] Indicates that a comment block contains documentation for a class with name. Optionally a header file and a header name can be specified.
- @date {date description} Starts a paragraph where one or more dates may be entered.
- @defgroup <name> (group title) Indicates that a comment block contains documentation for a group of classes, files or namespaces.
- @endlink This command ends a link that is started with the @link command.
- @enum <name> Indicates that a comment block contains documentation for an enumeration.
- @example <file-name> Indicates that a comment block contains documentation for a source code example.
- @exception <exception-object> {exception description} Starts an exception description for an exception object with name <exception-object>. Followed by a description of the exception.
- @file [<name>] Indicates that a comment block contains documentation for a source or header file with name <name>.
- @fn (function declaration) Indicates that a comment block contains documentation for a function (either global or as a member of a class).
- @include <file-name> This command can be used to include a source file as a block of code. The command takes the name of an include file as an argument.
- @interface <name> Indicates that a comment block contains documentation for an interface with name <name>.
- @link <link-object> This command can be used to create a link to an object (a file, class, or member) with a user specified link-text. The link command should end with an @endlink command.
- @name (header) This command turns a comment block into a header definition of a member group.
- @namespace <name> Indicates that a comment block contains documentation for a namespace with name <name>.
- @package <name> Indicates that a comment block contains documentation for a Java package with name <name>.
- @param <parameter-name> {parameter description} Starts a parameter description for a function parameter with name <parameter-name>. Followed by a description of the parameter.
- @return {description of the return value} Starts a return value description for a function.
- @retval <return value> {description} Starts a return value description for a function with name <return value>. Followed by a description of the return value.
- @struct <name> [<header-file>] [<header-name>] Indicates that a comment block contains documentation for a struct with name <name>.
- @test {paragraph describing a test case} Starts a paragraph where a test case can be described.
- @union <name> [<header-file>] [<header-name>] Indicates that a comment block contains documentation for a union with name <name>.
- @var (variable declaration) Indicates that a comment block contains documentation for a variable or enum value (either global or as a member of a class).
- @version {version number} Starts a paragraph where one or more version strings may be entered.
- @warning {warning message} Starts a paragraph where one or more warning messages may be entered.
References
1."C Style Guide", Doland, J. et. al., SEL-94-003, Software Engineering Laboratory Series, Goddard Space Flight Center, August 1994.
2.Effective C++, Meyers. S., Addison-Wesley Professional Computing Series, 1992.
3.C++ Primer, 2nd Edition, Lippman, S., AT&T Bell Laboratories, 1991.
4."Programming in C++ Rules and Recommendations", Henricson, M. and Nyquist, E., Ellemtel Telecommunication Systems Laboratories, 1990-1992.
5.C++ Style Guide, Version 1.0, Software and Automation Systems Branch, Goddard Space Flight Center, July 1992.
6."C++ Programming Style Guides", Eckel, B., UNIX Review, March 1995.
7."C++ Coding Standard", http://www.chris-lott.org/resources/cstyle/CppCodingStandard.html.