[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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).
5.1 Named Return Values in C++ Giving a name to C++ function return values. 5.2 Minimum and Maximum Operators in C++ C++ Minimum and maximum operators. 5.3 goto
and Destructors in GNU C++Goto is safe to use in C++ even when destructors are needed. 5.4 Declarations and Definitions in One Header You can use a single C++ header file for both declarations and definitions. 5.5 Where's the Template? Methods for ensuring that exactly one copy of each needed template instantiation is emitted. 5.6 Extracting the function pointer from a bound pointer to member function You can extract a function pointer to the method denoted by a `->*' or `.*' expression. 5.7 Type Abstraction using Signatures You can specify abstract types to get subtype polymorphism independent from inheritance.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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
at 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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
a >? 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 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
The compiler still forbids using goto
to
enter a scope that requires constructors.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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
#pragma interface "subdir/objects.h"
The second form of this directive is useful for the case where you have multiple headers with the same name in different directories. If you use this form, you must specify the same string to `#pragma implementation'.
#pragma implementation
#pragma implementation "objects.h"
If you use `#pragma implementation' with no argument, it applies to an include file with the same basename(2) as your source file. For example, in `allclass.cc', giving just `#pragma implementation' by itself is equivalent to `#pragma implementation "allclass.h"'.
In versions of GNU C++ prior to 2.6.0 `allclass.h' was treated as an implementation file whenever you would include it from `allclass.cc' even if you never specified `#pragma implementation'. This was deemed to be more trouble than it was worth, however, and disabled.
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). If all calls to the function can be inlined, you can avoid emitting the function by compiling with `-fno-implement-inlines'. If any calls were not inlined, you will get linker errors.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
C++ templates are the first language feature to require more intelligence from the environment than one usually finds on a UNIX system. Somehow the compiler and linker have to make sure that each template instance occurs exactly once in the executable if it is needed, and not at all otherwise. There are two basic approaches to this problem, which I will refer to as the Borland model and the Cfront model.
When used with GNU ld version 2.8 or later on an ELF system such as Linux/GNU or Solaris 2, or on Microsoft Windows, g++ supports the Borland model. On other systems, g++ implements neither automatic model.
A future version of g++ will support a hybrid model whereby the compiler will emit any instantiations for which the template definition is included in the compile, and store template definitions and instantiation context information into the object file for the rest. The link wrapper will extract that information as necessary and invoke the compiler to produce the remaining instantiations. The linker will then combine duplicate instantiations.
In the mean time, you have the following options for dealing with template instantiations:
This is your best option for application code written for the Borland
model, as it will just work. Code written for the Cfront model will need to be
modified so that the template definitions are available at one or more points
of instantiation; usually this is as simple as adding #include
<tmethods.cc>
to the end of each template header.
For library code, if you want the library to provide all of the template instantiations it needs, just try to link all of its object files together; the link will fail, but cause the instantiations to be generated as a side effect. Be warned, however, that this may cause conflicts if multiple libraries try to provide the same instantiations. For greater control, use explicit instantiation as described in the next option.
#include "Foo.h" #include "Foo.cc" template class Foo<int>; template ostream& operator << (ostream&, const Foo<int>&); |
for each of the instances you need, and create a template instantiation library from those.
If you are using Cfront-model code, you can probably get away with not using `-fno-implicit-templates' when compiling files that don't `#include' the member template definitions.
If you use one big file to do the instantiations, you may want to compile it without `-fno-implicit-templates' so you get all of the instances required by your explicit instantiations (but not by any other files) without having to specify them as well.
g++ has extended the template instantiation syntax outlined in the Working Paper to allow forward declaration of explicit instantiations and instantiation of the compiler support data for a template class (i.e. the vtable) without instantiating any of its members:
extern template int max (int, int); inline template class Foo<int>; |
template class A<int>; template ostream& operator << (ostream&, const A<int>&); |
This strategy will work with code written for either model. If you are using code written for the Cfront model, the file containing a class template and the file containing its member templates should be implemented in the same translation unit.
A slight variation on this approach is to instead use the flag `-falt-external-templates'; this flag causes template instances to be emitted in the translation unit that implements the header where they are first instantiated, rather than the one which implements the file where the templates are defined. This header must be the same in all translation units, or things are likely to break.
See section Declarations and Definitions in One Header, for more discussion of these pragmas.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In C++, pointer to member functions (PMFs) are implemented using a wide pointer of sorts to handle all the possible call mechanisms; the PMF needs to store information about how to adjust the `this' pointer, and if the function pointed to is virtual, where to find the vtable, and where in the vtable to look for the member function. If you are using PMFs in an inner loop, you should really reconsider that decision. If that is not an option, you can extract the pointer to the function that would be called for a given object/PMF pair and call it directly inside the inner loop, to save a bit of time.
Note that you will still be paying the penalty for the call through a function pointer; on most modern architectures, such a call defeats the branch prediction features of the CPU. This is also true of normal virtual function calls.
The syntax for this extension is
extern A a; extern int (A::*fp)(); typedef int (*fptr)(A *); fptr p = (fptr)(a.*fp); |
You must specify `-Wno-pmf-conversions' to use this extension.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In GNU C++, you can use the keyword signature
to define a
completely abstract class interface as a datatype. You can connect this
abstraction with actual classes using signature pointers. If you want to use
signatures, run the GNU compiler with the `-fhandle-signatures'
command-line option. (With this option, the compiler reserves a second keyword
sigof
as well, for a future extension.)
Roughly, signatures are type abstractions or interfaces of classes. Some
other languages have similar facilities. C++ signatures are related to ML's
signatures, Haskell's type classes, definition modules in Modula-2, interface
modules in Modula-3, abstract types in Emerald, type modules in Trellis/Owl,
categories in Scratchpad II, and types in POOL-I. For a more detailed discussion
of signatures, see Signatures: A Language Extension for Improving Type
Abstraction and Subtype Polymorphism in C++ by Gerald Baumgartner and
Vincent F. Russo (Tech report CSD--TR--95--051, Dept. of Computer Sciences,
Purdue University, August 1995, a slightly improved version appeared in
Software--Practice & Experience, 25(8), pp. 863--889, August
1995). You can get the tech report by anonymous FTP from
ftp.cs.purdue.edu
in `pub/gb/Signature-design.ps.gz'.
Syntactically, a signature declaration is a collection of member function
declarations and nested type declarations. For example, this signature
declaration defines a new abstract type S
with member functions
`int foo ()' and `int bar (int)':
signature S { int foo (); int bar (int); }; |
Since signature types do not include implementation definitions, you cannot write an instance of a signature directly. Instead, you can define a pointer to any class that contains the required interfaces as a signature pointer. Such a class implements the signature type.
To use a class as an implementation of S
, you must ensure that
the class has public member functions `int foo ()' and `int
bar (int)'. The class can have other member functions as well, public or
not; as long as it offers what's declared in the signature, it is suitable as an
implementation of that signature type.
For example, suppose that C
is a class that meets the
requirements of signature S
(C
conforms to
S
). Then
C obj; S * p = &obj; |
defines a signature pointer p
and initializes it to point to an
object of type C
. The member function call `int i = p->foo
();' executes `obj.foo ()'.
Abstract virtual classes provide somewhat similar facilities in standard C++. There are two main advantages to using signatures instead:
T
is a subtype of a signature type S
independent of
any inheritance hierarchy as long as all the member functions declared in
S
are also found in T
. So you can define a subtype
hierarchy that is completely independent from any inheritance (implementation)
hierarchy, instead of being forced to use types that mirror the class
inheritance hierarchy.
There is one more detail about
signatures. A signature declaration can contain member function
definitions as well as member function declarations. A signature member
function with a full definition is called a default implementation;
classes need not contain that particular interface in order to conform. For
example, a class C
can conform to the signature
signature T { int f (int); int f0 () { return f (0); }; }; |
whether or not C
implements the member function `int f0
()'. If you define C::f0
, that definition takes precedence;
otherwise, the default implementation S::f0
applies.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |