Go to the previous, next section.

Extensions to the C++ Language

The GNU compiler provides these extensions to the C++ language (and you can also use most of the C language extensions in your C++ programs). If you want to write code that checks whether these features are available, you can test for the GNU compiler the same way as for C programs: check for a predefined macro __GNUC__. You can also use __GNUG__ to test specifically for GNU C++ (see section `Standard Predefined Macros' in The C Preprocessor).

Named Return Values in C++

GNU C++ extends the function-definition syntax to allow you to specify a name for the result of a function outside the body of the definition, in C++ programs:

type
functionname (args) return resultname;
{ 
  ...
  body
  ...
}

You can use this feature to avoid an extra constructor call when a function result has a class type. For example, consider a function m, declared as `X v = m ();', whose result is of class X:

X
m ()
{
  X b;
  b.a = 23;
  return b; 
}

Although m appears to have no arguments, in fact it has one implicit argument: the address of the return value. At invocation, the address of enough space to hold v is sent in as the implicit argument. Then b is constructed and its a field is set to the value 23. Finally, a copy constructor (a constructor of the form `X(X&)') is applied to b, with the (implicit) return value location as the target, so that v is now bound to the return value.

But this is wasteful. The local b is declared just to hold something that will be copied right out. While a compiler that combined an "elision" algorithm with interprocedural data flow analysis could conceivably eliminate all of this, it is much more practical to allow you to assist the compiler in generating efficient code by manipulating the return value explicitly, thus avoiding the local variable and copy constructor altogether.

Using the extended GNU C++ function-definition syntax, you can avoid the temporary allocation and copying by naming r as your return value as the outset, and assigning to its a field directly:

X
m () return r;
{
  r.a = 23; 
}

The declaration of r is a standard, proper declaration, whose effects are executed before any of the body of m.

Functions of this type impose no additional restrictions; in particular, you can execute return statements, or return implicitly by reaching the end of the function body ("falling off the edge"). Cases like

X
m () return r (23);
{
  return; 
}

(or even `X m () return r (23); { }') are unambiguous, since the return value r has been initialized in either case. The following code may be hard to read, but also works predictably:

X
m () return r;
{
  X b;
  return b; 
}

The return value slot denoted by r is initialized at the outset, but the statement `return b;' overrides this value. The compiler deals with this by destroying r (calling the destructor if there is one, or doing nothing if there is not), and then reinitializing r with b.

This extension is provided primarily to help people who use overloaded operators, where there is a great need to control not just the arguments, but the return values of functions. For classes where the copy constructor incurs a heavy performance penalty (especially in the common case where there is a quick default constructor), this is a major savings. The disadvantage of this extension is that you do not control when the default constructor for the return value is called: it is always called at the beginning.

Minimum and Maximum Operators in C++

It is very convenient to have operators which return the "minimum" or the "maximum" of two arguments. In GNU C++ (but not in GNU C),

a <? b
is the minimum, returning the smaller of the numeric values a and b;

a >? b
is the maximum, returning the larger of the numeric values a and b.

These operations are not primitive in ordinary C++, since you can use a macro to return the minimum of two things in C++, as in the following example.

#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))

You might then use `int min = MIN (i, j);' to set min to the minimum value of variables i and j.

However, side effects in X or Y may cause unintended behavior. For example, MIN (i++, j++) will fail, incrementing the smaller counter twice. A GNU C extension allows you to write safe macros that avoid this kind of problem (see section Naming an Expression's Type). However, writing MIN and MAX as macros also forces you to use function-call notation notation for a fundamental arithmetic operation. Using GNU C++ extensions, you can write `int min = i <? j;' instead.

Since <? and >? are built into the compiler, they properly handle expressions with side-effects; `int min = i++ <? j++;' works correctly.

goto and Destructors in GNU C++

In C++ programs, you can safely use the goto statement. When you use it to exit a block which contains aggregates requiring destructors, the destructors will run before the goto transfers control. (In ANSI C++, goto is restricted to targets within the current block.)

The compiler still forbids using goto to enter a scope that requires constructors.

Declarations and Definitions in One Header

C++ object definitions can be quite complex. In principle, your source code will need two kinds of things for each object that you use across more than one source file. First, you need an interface specification, describing its structure with type declarations and function prototypes. Second, you need the implementation itself. It can be tedious to maintain a separate interface description in a header file, in parallel to the actual implementation. It is also dangerous, since separate interface and implementation definitions may not remain parallel.

With GNU C++, you can use a single header file for both purposes.

Warning: The mechanism to specify this is in transition. For the nonce, you must use one of two #pragma commands; in a future release of GNU C++, an alternative mechanism will make these #pragma commands unnecessary.

The header file contains the full definitions, but is marked with `#pragma interface' in the source code. This allows the compiler to use the header file only as an interface specification when ordinary source files incorporate it with #include. In the single source file where the full implementation belongs, you can use either a naming convention or `#pragma implementation' to indicate this alternate use of the header file.

#pragma interface
Use this directive in header files that define object classes, to save space in most of the object files that use those classes. Normally, local copies of certain information (backup copies of inline member functions, debugging information, and the internal tables that implement virtual functions) must be kept in each object file that includes class definitions. You can use this pragma to avoid such duplication. When a header file containing `#pragma interface' is included in a compilation, this auxiliary information will not be generated (unless the main input source file itself uses `#pragma implementation'). Instead, the object files will contain references to be resolved at link time.

#pragma implementation
#pragma implementation "objects.h"
Use this pragma in a main input file, when you want full output from included header files to be generated (and made globally visible). The included header file, in turn, should use `#pragma interface'. Backup copies of inline member functions, debugging information, and the internal tables used to implement virtual functions are all generated in implementation files.

`#pragma implementation' is implied whenever the basename(3) of your source file matches the basename of a header file it includes. There is no way to turn this off (other than using a different name for one of the two files). In the same vein, if you use `#pragma implementation' with no argument, it applies to an include file with the same basename as your source file. For example, in `allclass.cc', `#pragma implementation' by itself is equivalent to `#pragma implementation "allclass.h"'; but even if you do not say `#pragma implementation' at all, `allclass.h' is treated as an implementation file whenever you include it from `allclass.cc'.

If you use an explicit `#pragma implementation', it must appear in your source file before you include the affected header files.

Use the string argument if you want a single implementation file to include code from multiple header files. (You must also use `#include' to include the header file; `#pragma implementation' only specifies how to use the file--it doesn't actually include it.)

There is no way to split up the contents of a single header file into multiple implementation files.

`#pragma implementation' and `#pragma interface' also have an effect on function inlining.

If you define a class in a header file marked with `#pragma interface', the effect on a function defined in that class is similar to an explicit extern declaration--the compiler emits no code at all to define an independent version of the function. Its definition is used only for inlining with its callers.

Conversely, when you include the same header file in a main source file that declares it as `#pragma implementation', the compiler emits code for the function itself; this defines a version of the function that can be found via pointers (or by callers compiled without inlining).

Go to the previous, next section.