United States    
COMPAQ STORE | PRODUCTS |
SERVICES | SUPPORT | CONTACT US | SEARCH
cxxtitle.gif (12116 bytes)
Compaq C++

Compaq C++
Using Compaq C++ for Tru64 UNIX Systems


Previous Contents Index

4.4.3 Constants in Function Returns

Because the return value cannot be an lvalue, a constant in a function return has no effect on the semantics of the return. However, using a constant in a function return does affect the type signature. For example:


static int f1( int a, int b) {;} 
const int (* const (f2[])) (int a, int b) = {f1}; 

In this example, the referenced type of the pointer value f1 in the initializer for f2[] is function (signed int, signed int), which returns signed int. This is incompatible with function (signed int, signed int), which returns const signed int.

You can omit the const of int because it affects only the constant return signature.

4.4.4 Pointers to Constants

The following example shows a type mismatch between a pointer to a char and a pointer to a const char that some compilers, other than the Compaq C++ compiler, may not find:


void foo (const char* argv[]) {} 
int main() 
{ 
        static char* args[2] = {"foo","bar"}; 
/* 'In this statement, the referenced type of the pointer value 
 "args" is "pointer to char"' which is not compatible with 
 "pointer to const char"'*/ 
        foo (args); 
return 0; 
} 

You can correct this example by changing static char to static const char. Use an explicit type cast to get an argument match only if no other option is available; such a cast may break on some C++ implementations.

4.5 Using typedefs

Using a synonym after a class, struct, or union prefix is illegal. Using a synonym in the names for constructors and destructors within the class declaration itself is also illegal.

In the following example, the illegal typedef specifier is commented out:


typedef struct { /* ...*/ } foo; 
// typedef struct foo foobar;             ** not legal 

For more information, see §r.7.1.3 of The C++ Programming Language, 2nd Edition.

4.6 Initializing References

Compaq C++ warns against initializing nonconstant references to refer to temporary objects. The following example demonstrates the problems that can result:


static void f() 
{ 
    int i = 5; 
    i++;        // OK 
    int &ri = 23; 
    ri++;       // In the initializer for ri, the initialization of a 
                // non-const reference requires a temporary for "23". 
} 

The issue of reference initialization arises most often in assignment operators and in copy constructors. Wherever possible, declare all reference arguments as const.

For more information, see §r.8.4.3 of The C++ Programming Language, 2nd Edition.

4.7 Using the switch and goto Statements

Branching around a declaration with an explicit or implicit initializer is not legal, unless the declaration is in an inner block that is completely bypassed. To satisfy this constraint, enclose the declaration in a block. For example:


int i; 
 
switch (i) { 
case 1: 
    int l = 0;     //not initialized at this case label 
    myint m = 0;   //not initialized at this case label 
    { 
    int j = 0;     // legal within the braces 
    myint m = 0;   // legal within the braces 
    } 
case 2: 
    break; 
// ...
} 

For more information on using the switch statement, see §r.6.4.2 of The C++ Programming Language, 2nd Edition.

4.8 Using Volatile Objects

You must supply the meaning of copy constructing and assigning from volatile objects, because the compiler generates no copy constructors or assignment operators that copy or assign from volatile objects. The following example contains examples of such errors, as noted in the comments:


class A { 
public: 
  A() { } 
  // A(volatile A&) { } 
  // operator=(volatile A&) { return 0; } 
}; 
 
void foo() 
{ 
  volatile A va; 
  A a; 
 
  A cca(va);  // error - cannot copy construct from volatile object 
  a = va;     // error - cannot assign from volatile object 
 
  return; 
} 

For more information, see §r.7.1.6 of The C++ Programming Language, 2nd Edition.

4.9 Preprocessing

Compaq C++ allows identifiers, but not expressions, on the #ifdef preprocessor directive. For example:


// this is not legal 
// #ifdef KERNEL && !defined(__POSIX_SOURCE) 

The following is the legal alternative:


// use this instead 
#if defined(KERNEL) && !defined(__POSIX_SOURCE) 

For more information, see §r.16.5 of The C++ Programming Language, 2nd Edition.

4.10 Managing Memory

The proper way to manage memory for a class is to overload the new and delete operators. This is in contrast to some older C++ implementations, which let you manage memory through assignment to the this pointer.

For more information, see §r.18.3.3 of The C++ Programming Language, 2nd Edition.

Program developers must take care that any user-defined new operators always return pointers to quadword aligned memory.

4.11 Size-of-Array Argument to delete Operator

If a size-of-array argument accompanies a delete operator, Compaq C++ ignores the argument and issues a warning. The following example includes an anachronistic use of the delete operator:


int main() 
{ 
        int *a = new int [20]; 
        int *b = new int [20]; 
        delete[20] a;     //old-style; argument ignored, warning issued 
        delete[] b; 
return 0; 
} 

4.12 Flushing the Output Buffer

Do not depend on the newline character (\n) to flush your terminal output buffer. A previous stream implementation might have done so, but this behavior is not in conformance with Version 2.0 of the AT&T iostream library. If you want to flush the output buffer, use the endl manipulator or the flush member function.

4.13 Missing Parenthesis Error Message

Situations occur in which a simple typographical error generates a missing parenthesis error message. In the following example, the class name CaseSensitive is incorrectly specified as Casesensitive in the constructor declaration:


class CaseSensitive { 
    void Test( const Casesensitive &foo ); 
}; 

As the compiler parses the argument declaration list, it first sees const, which it interprets as a type specifier. The compiler then sees Casesensitive, which it interprets as a dname. Among the next legal tokens are the equal sign, comma, and closing parenthesis. Upon finding an ampersand, the compiler expects a closing parenthesis. With all other possibilities exhausted, the compiler has what appears to be a legal argument declaration list, after which the closing parenthesis is the only allowable token. The compiler expected one thing but encountered something else. Often, inserting newline characters can isolate the offending token.

4.14 Segmentation Faults

If you encounter a segmentation fault (signal SEGV) while running your program, it might be because you built your binary with the wrong linker. Use the cxx command, not the ld command, to build a binary; otherwise, the run-time startup and other crucial code will not build properly.

4.15 Source File Extensions

Compaq C++ automatically treats files with a .c extension as C language source files and passes the files to the cc command. For Compaq C++ to compile them, your files must have one of the following extensions:


.cxx        .CXX 
.cpp        .CPP 
.cc         .CC 
.C 

You also can use the -x option to direct the compiler to ignore file-name extensions and treat all named files, other than those with an .a or .o extension, as C++ source files.

4.16 Incrementing Enumerations

Some other C++ implementations let you perform integer arithmetic, including ++, on enumerated types; Compaq C++ does not allow this.

4.17 Overloading Disambiguation

Compaq C++ applies the conversions specified in The Annotated C++ Reference Manual more strictly than do some C++ implementations. This can cause Compaq C++ to interpret some calls to overloaded functions as ambiguous, even though some other C++ implementations may be able to process them. The following example shows one of these ambiguous calls to overloaded functions:


#include <iostream.hxx> 
 
enum logical { false, true }; 
logical false1 = false; /* const unsigned int */ 
unsigned int false2 = 0; 
const int false3 = 0; 
 
void foo(void*)  { cout << "foo(void*)\\n"; } 
void foo(int)  { cout << "foo(int)\\n"; } 
 
main() 
{ 
   foo(false1);  // Constant expression that is not an exact match for 
                 // int.  Can be converted using standard conversions 
                 // to both int and void* 
   foo(false2);  // not a constant expression 
   foo(false3);  // exact match of int 
} 

In this example, false1 is ambiguous. As an unsigned const int with a value of 0, it can be converted either to void* or to int.

The following example shows how to properly declare the logical:


   enum logical  { false = 1, true }; 

4.18 Variables Declared More than Once

Some other C++ implementation might handle scoping differently from Compaq C++, as shown by the following code fragment:


foo(int dup)  // first dup declared 
{ 
  // first dup used 
  for(int dup; dup < 10; dup++)  // second dup declared 
  { 
    // second dup used 
    int dup;  // third dup declared 
    // third dup used 
  } 
  // first dup used 
} 
 
main() 
{ 
  foo(5); 
} 

In this example, dup is used three times: once in the formal parameter declaration, once in the for statement declaration, and once in the for block. The third declaration is correct, because it is within a block. The second declaration, should be flagged as an error because it is not within a separate block. Compaq C++ will flag this as an error.

4.19 Guidelines for Writing Clean 64-Bit Code

Paying careful attention to data types can ensure that your code works on both 32-bit and 64-bit systems. Use the following guidelines to write clean 64-bit code:

For more information, see the Tru64 UNIX Migration Guide.


Chapter 5
Using Templates

A C++ template is a framework for defining a set of classes or functions. The process of instantiation creates a particular class or function of the set by resolving the C++ template with a group of arguments that are themselves types or values. For example:


template <class T> class Array { 
    T *data; 
    int size; 
public: 
    T &operator[](int); 
    /* ...*/ 
};    

The code in this example declares a C++ class template named Array that has two data members named data and size and one subscript operator member function. Array<int> instantiates Array with type int. This instantiation generates the following class definition:


class Array { 
    int *data; 
    int size; 
public: 
    int &operator[](int); 
    /* ...*/ 
};    

Compaq C++ supports instantiation of C++ class, function, and static data member templates. The following sections describe the alternative methods available for instantiating templates.

Automatic Instantiation

This method instantiates templates automatically, as they are needed by your application. Special conventions must be followed regarding the name and location of template declaration and definition files. You can use a name mapping file to direct the compiler to the location of the template definition file. To get started quickly using automatic instantiation, see laz Section 5.1. For details, see Section 5.2.

Manual Instantiation

Compaq C++ provides the following methods to manually instantiate templates:

5.1 Automatic Instantiation Quick Start

By default, Compaq C++ does not instantiate any template requests made by the application at compile time. Instead it creates instantiation source files in a repository. The repository is a directory where Compaq C++ stores various information about the templates being instantiated. The files in the repository contain the source used to generate the requested instantiations. Consider the following example:


 
//main.cxx 
#include "Array.h"           //template declaration file 
#include <String.hxx>        //argument declaration file 
 
int main() 
{ 
    Array<String> v; 
 
    v[0] = "hello world";    //request of Array's subscript 
                             //operator 
    return 0; 
} 
 

The header file Array.h is referred to as the template declaration file. To organize a program to use automatic instantiation effectively, you must place the declarations of class and function templates into a header file. For more information, see Section 5.2.4.

The contents of Array.h are as follows:


template <class T> class Array { 
    T *data; 
    int size; 
public: 
    T &operator[](int); 
}; 

The definitions or bodies of function and class member function templates should appear in a separate header file referred to as the template definition file. For more information regarding the contents of template definition files, see Section 5.2.5.

The template definition file should have the same base name as its corresponding template declaration file but with a different file extension. In the current example, the template definition file is named Array.cxx and is located in the same directory as Array.h. The contents of Array.cxx are as follows:


 
template <class T> 
T & Array<T>::operator[](int i) { 
    return *(data + i); 
} 
 

For more details on template definition file lookup rules, see Section 5.2.7.1.

In the previous example of main.cxx, String is the type used to instantiate the class template Array. Declarations of various types that are used to instantiate a particular template must be defined within a header file. A compile-time diagnostic will be issued if Compaq C++ compiles an instantiation whose argument type was defined in the source file instead of in a header file. For example:


//error.cxx 
#include "Array.h" 
 
struct MyString {  
    /* ...*/ 
}; 
 
int main() 
{ 
    Array<MyString> v; 
 
    v[0] = "Hello World"; 
    return 0; 
} 

In this example, an error occurs because Compaq C++ does not duplicate the definition of MyString in any instantiation source file created as a result of compiling the source file error.cxx.

Because Compaq C++ performs automatic template instantiation by default, you do not need to specify the -pt option on the command line. To build the main program, use a cxx command such as the following:


cxx -I./include main.cxx 

This command assumes that main.cxx is located in the current directory and Array.h and Array.cxx are in the ./include subdirectory.

Compaq C++ creates the default repository in ./cxx_repository. For more details about the contents of repositories, see Section 5.2.3.

One of the instantiation requests needed by the source file main.cxx is an instantiation of the Array's subscript member function, Array<T>::operator[](int), with type String. To satisfy this request, Compaq C++ will generate the following instantiation source file in the default repository:


 
// Array__T6String.cxx 
#include "Array.h"     //template declaration file 
#include <String.h>    //argument declaration file 
#include "Array.cxx"   //template definition file 
 
typedef Array<String> __dummy_; 
 

Once compilation of main.cxx completes, Compaq C++ invokes a prelinker to determine the instantiation requests generated by the application. For each request, the prelinker reinvokes Compaq C++ in a special template request mode to compile the necessary instantiation. The resulting object files are stored in a repository for use when Compaq C++ links the application.

The following are some other helpful notes to get started quickly:


Previous Next Contents Index
  

1.800.AT.COMPAQ

privacy and legal statement