Go to the first, previous, next, last section, table of contents.
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).
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.
Both the C and C++ standard have the concept of volatile objects. These are normally accessed by pointers and used for accessing hardware. The standards encourage compilers to refrain from optimizations concerning accesses to volatile objects that it might perform on non-volatile objects. The C standard leaves it implementation defined as to what constitutes a volatile access. The C++ standard omits to specify this, except to say that C++ should behave in a similar manner to C with respect to volatiles, where possible. The minimum either standard specifies is that at a sequence point all previous accesses to volatile objects have stabilized and no subsequent accesses have occurred. Thus an implementation is free to reorder and combine volatile accesses which occur between sequence points, but cannot do so for accesses across a sequence point. The use of volatiles does not allow you to violate the restriction on updating objects multiple times within a sequence point.
In most expressions, it is intuitively obvious what is a read and what is a write. For instance
volatile int *dst = <somevalue>; volatile int *src = <someothervalue>; *dst = *src;
will cause a read of the volatile object pointed to by src and stores the
value into the volatile object pointed to by dst. There is no
guarantee that these reads and writes are atomic, especially for objects
larger than int
.
Less obvious expressions are where something which looks like an access is used in a void context. An example would be,
volatile int *src = <somevalue>; *src;
With C, such expressions are rvalues, and as rvalues cause a read of the object, gcc interprets this as a read of the volatile being pointed to. The C++ standard specifies that such expressions do not undergo lvalue to rvalue conversion, and that the type of the dereferenced object may be incomplete. The C++ standard does not specify explicitly that it is this lvalue to rvalue conversion which is responsible for causing an access. However, there is reason to believe that it is, because otherwise certain simple expressions become undefined. However, because it would surprise most programmers, g++ treats dereferencing a pointer to volatile object of complete type in a void context as a read of the object. When the object has incomplete type, g++ issues a warning.
struct S; struct T {int m;}; volatile S *ptr1 = <somevalue>; volatile T *ptr2 = <somevalue>; *ptr1; *ptr2;
In this example, a warning is issued for *ptr1
, and *ptr2
causes a read of the object pointed to. If you wish to force an error on
the first case, you must force a conversion to rvalue with, for instance
a static cast, static_cast<S>(*ptr1)
.
When using a reference to volatile, g++ does not treat equivalent expressions as accesses to volatiles, but instead issues a warning that no volatile is accessed. The rationale for this is that otherwise it becomes difficult to determine where volatile access occur, and not possible to ignore the return value from functions returning volatile references. Again, if you wish to force a read, cast the reference to an rvalue.
As with gcc, g++ understands the C99 feature of restricted pointers,
specified with the __restrict__
, or __restrict
type
qualifier. Because you cannot compile C++ by specifying the -std=c99
language flag, restrict
is not a keyword in C++.
In addition to allowing restricted pointers, you can specify restricted references, which indicate that the reference is not aliased in the local context.
void fn (int *__restrict__ rptr, int &__restrict__ rref) { ... }
In the body of fn
, rptr points to an unaliased integer and
rref refers to a (different) unaliased integer.
You may also specify whether a member function's this pointer is
unaliased by using __restrict__
as a member function qualifier.
void T::fn () __restrict__ { ... }
Within the body of T::fn
, this will have the effective
definition T *__restrict__ const this
. Notice that the
interpretation of a __restrict__
member function qualifier is
different to that of const
or volatile
qualifier, in that it
is applied to the pointer rather than the object. This is consistent with
other compilers which implement restricted pointers.
As with all outermost parameter qualifiers, __restrict__
is
ignored in function definition matching. This means you only need to
specify __restrict__
in a function definition, rather than
in a function prototype as well.
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"
#pragma implementation
#pragma implementation "objects.h"
`#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.
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:
#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 (with
extern
), instantiation of the compiler support data for a
template class (i.e. the vtable) without instantiating any of its
members (with inline
), and instantiation of only the static data
members of a template class, without the support data or member
functions (with (static
):
extern template int max (int, int); inline template class Foo<int>; static 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.
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);
For PMF constants (i.e. expressions of the form `&Klasse::Member'), no object is needed to obtain the address of the function. They can be converted to function pointers directly:
fptr p1 = (fptr)(&A::foo);
You must specify `-Wno-pmf-conversions' to use this extension.
Go to the first, previous, next, last section, table of contents.