cartobase  5.0.5
Keeping Portability

A few tips for portable programming :

It's a list of little things

  • always use std:: in .h files before all classes of the standard namespace:
    • string
    • streams:
      • istream
      • ostream
      • ifstream
      • ofstream
      • cout
      • cerr
      • cin
      • streambuf
      • ...
    • iomanips:
      • ios
      • setw
      • setprec
      • ...
    • STL classes:
      • vector
      • set
      • map
      • multimap
      • ...
  • explicitly use the namespace std in .cc files:
using namespace std;

#include <cstdlib> (put it after the #include lines) -> no need to use std:: everywhere in .cc files

  • avoid writing "using something" in a .h (it's not a portability issue but a potential cause of conflicts)
  • when standard headers exist in both forms <something.h> and <something>, always use the <something> version (without .h):
#include <iostream>
#include <fstream>
#include <streambuf>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <algorithm> // and NOT <algo.h> !

etc... Using *.h variants causes conflicts in modern compilers (gcc 3 and later), and even with older ones (egcs and gcc 2.95) in some conditions (vector<bool> for instance has diffent implementations in <vector> and <vector.h> with distinct internal organization and objects sizes, and mixing them is a source of ununderstandable crashes and bugs...)

  • don't hesitate to include <iostream> as soon as cin or cout is used in a source file, on some systems/compilers they are not always needed but thay may not be defined when <fstream> is included and not <iostream>
  • do NOT use:
#include <stl.h>
#include <algo.h> // -> use #include <algorithm>
  • do NOT use:

    MAXFLOAT etc

    but rather:

    FLT_MAX

    FLT_MAX is defined in <float.h>

    Or even better: use std::numeric_limits, which is part of standard C++ since gcc 3.x, but also available in cartobase with older compilers:

  • do NOT use <values.h>

    Some systems don't provide it. Some (old) compilers do not provide <limits> either. Instead, use the following:

  • Always include <cartobase/config/cartobase_config.h> before using file IO functions: cartobase config takes care of making use of 64 bit file IO functions.
  • do NOT re-use variable declarations from a loop to another one in the same code block:
for(int i=0; i<5; ++i)
cout << "toto\n";
for(int i=0; i<10; ++i)
cout << "tutu\n";

but rather:

int i;
for(i=0; i<5; ++i)
cout << "toto\n";
for(i=0; i<10; ++i)
cout << "tutu\n";

I know it should not cause any problem in principle, but even the Intel compiler (which is not so bad in other situations) doesn't accept such re-declarations. In any case, it's very simple to avoid, so please do it...

  • do NOT use arrays allocated directly with a variable size:
int dim = getDim();
char toto[ dim ];

I personnally liked such a convenient code, and it works well with gcc, but other compilers don't allow it (it's simply not correct C). We have to go back to more primitive forms (and far less convenient) such as:

int dim = getDim();
char *toto = new char[ dim ];
// ... use the array ...
// be careful not to have a return or throw statement before delete[],
// (otherwise there will be a memory leak...)
delete[] toto;

You can also use STL vectors, or a carto::block, instead in most situations:

#include <vector>
int dim = getDim();
std::vector<char> toto( dim );
// utilisation
toto[12] = 5;
  • Avoid using a number of "dangerous" words which can be reserved keywords in some specific compilers or systems, like for instance:
    • near, far (which are calling modes on Windows)
    • small, large
  • non-portable functions, specific to Unix, etc...
    • all (or most) of <unistd.h> etc.
    • rint() is defined in <cartobase/config/cartobase_config.h>
    • max() is not defined in every compiler. But STL provides some templated versions of it
    • directories manipulation fonctions: opendir(), closedir(), readdir() - use carto::FileUtil and carto::Directory
    • mkdir( name, access_rights ) -> mkdir( name ) (on windows, no access rights, only 1 parameter). Use carto::Directory.
    • named pipes (which don't exist on older Windows)
    • isnan() is defined in <cartobase/config/cartobase_config.h>
    • memory mapping, the API is completely different on Windows: xxxFileMapping() functions: use cartobase allocators
    • ...
  • some functions are present in different headers on different systems. When we find such functions that may be useful, we wrap them in cartobase header files.