Writing Portable C++

Spanning the OS chasm


(image: kde)

Table of Contents

  1. Use config.h
  2. Avoid NULL
  3. On the scope of temporaries
  4. Don't initialize const in definitions
  5. Don't use arrays with runtime sizing
  6. Remove default args from method implementation
  7. Don't use gethostname() or getdomainname()
  8. Using ksize_t and socket.h
  9. No semicolon after Q_OBJECT
  10. Be careful while passing temporaries

Most (but not all) of the people who helped put this together: Stephan Kulow, Claus Reimann, Uwe Thiem and Denis Pershin. Thanks, fellows.


    Use config.h

    Use config.h, which is created by configure, very liberally. There are many constants that it defines to help make your code portable across platforms.

    top


    Avoid NULL

    The constant NULL is known to cause trouble on some platforms due to different word sizes and stricter compilers. This is especially important for method declarations:
    	class foo {
    		// DO this
    		void member( char *value = 0 );
    		// DON'T do this
    		void member( char *value = NULL );
    	};
    

    top


    On the scope of temporaries

    Some compilers do not accept the following code:

    	for(int i=0; i<n; i++){ /* do something */ };
    	for(int i=0; i<n; i++){ /* do something else*/ };
    

    In this case, i will have already been defined in that scope and the compiler will generate an error.

    top


    Don't initialize const in definitions

    Do not initialize const members of a class inside the class definition itself

            class foo {
              const int value = 42;  // DON'T do this!!
            };
    

    The correct way is to define it inside the class constructor:

            class foo {
              foo();
              const int value;
            };
            foo::foo() : value(42){ /* do something */ }
    

    But: Since this is a constant, I would think you want a static data member. Otherwise, every foo-object will need the space to store that integer. You want something like:

            class foo {
              static const int value;
            };
            const foo::value = 42;
    
    BTW: Actually, initialization of const static members is a new feature. The ANSI C++ Draft dated 2 December 1996 allows the following code:
            class foo {
              static const int value = 42;
            };
    

    That's what you want, right? But there are only a VERY few compiler allowing this! Program in the spirit of portable code and use the other way.

    top


    Don't use arrays with runtime sizing

    You may use this with gcc:

    	{
    		char array[count + 3];
    		fillArray(array);
    	}
    

    but this is not portable. AIX' xlC doesn't know it and Solaris' CC doesn't know it too. So, please use the following:

    	{
    		char *array = new char[count + 3];
    		fillArray(array);
    		.
    		.
    		.
    		delete [] array;
    	}
    

top


Remove default args from method implementation

Default arguments should only be specified in the class declaration. Do NOT include them in the implementation of a method.
// myclass.cpp
// *WRONG*
void KMyClass:myMethod( int a=10, const char *str="A String")
{
	...
}

// Correct
void KMyClass:myMethod( int a, const char *str)
{
	...
}

top


Don't use gethostname() or getdomainname()

gethostname() and getdomainname() are not part of the POSIX specification. Use utsname() instead. It is declared in sys/utsname.h.

top


Using ksize_t and socket.h

Some functions in /usr/include/sys/socket.h are defined differently on 32-bit Unices like Linux/Intel and 64-bit Unices like Linux/Alpha. In particular they differ in the type of one of their arguments. If you use any function from socket.h please have a look at the following table whether your function is one of them. If it is, you need to include config.h, where ksize_t is defined:

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Now you have to pass an ksize_t instead of int or size_t as the relevant argument to this function. The configure stuff in KDE will take care of the correct type.

Table of relevant functions
Function Relevant Argument
bind() 3rd
getsocketname() 3rd
connect() 3rd
getpeername() 3rd
sendto() 6th
recvfrom() 6th
getsockopt() 5th
setsockopt() 5th
accept() 3rd
this section courtesy of Uwe Thiem

top


No semicolon after Q_OBJECT

Don't put a semicolon after a Q_OBJECT declaration:

class KFoo : public QWidget
{
	// NO
	Q_OBJECT;

	// Yes
	Q_OBJECT

The HP-UX CC compiler cannot handle two consecutive semicolons. It is a silly compiler, but we must comply if we want HP-UX to be a supported platform.

top


Be careful while passing temporaries

Don't pass a pointer or reference to a temporary variable to another function if you are not sure when it will be deleted.
	// Naughty!
	setColor( &(QColor(black)) );

	// Nice
	QColor color(black);
	setColor( &color );

top


back

Written and maintained by: Sirtaj S. Kang (taj@kde.org)
Last modified: Mon Jan 24 15:00:48 EST 2000