Previous Next Contents Index Doc Set Home


Migration Guide

A


This section is intended to help users of earlier versions of C++ (3.0, 3.0.1, 4.0, 4.0.1 and 4.1) port their code to C++ 4.2. If you have code that compiles and runs under C++ 3.0, and would like to have it compile and run under C++ 4.2, this is, in most cases, as easy as recompiling and relinking the code.


Note - C++ 4.2 object code is not compatible with C++ 3.0 object code, so you must recompile your code, including any libraries, which might contain C++ code. C++ 4.2 object code is compatible with C++ 4.1 and 4.0 object code.
This document resides in the README directory; it is included in both ASCII and PostScriptTM format. The PostScript file has a .ps suffix.


The Language

C++ is an actively changing language. There is an ANSI committee hard at work trying to generate a standard for the language, but that is still years away. In the meantime, there are the Annotated Reference Manual (ARM) and C++ 3.0, although these leave much to be desired.

When writing a compiler, you need hard facts about every aspect of the language, and when you can't find a precise definition, you have to make the best guess you can. The developers chose to follow the ARM whenever it was clear enough, and to use the ongoing work of the ANSI committee, as described in the Draft Working Paper (DWP) to help clarify murky areas. The result is their best guess at what the language will become, but you can expect changes with the next release. Sun is actively involved in the ANSI committee and the entire C++ standardization effort, so the developers are tracking its progress closely.

The compiler supports the entire language described in the ARM, including templates and exceptions. It also includes support for wide characters, including a separate type for wchar_t. SPARCompiler C++ 4.2 is fully integrated with Solaris 2.x internationalization features. There is an extended long integer (long long int) and a true long double type.

Sun is aware that there is a lot of code that compiles with some version of C++ 3.0, but is not legal under the current (or possibly any) language definition. The compiler detects and flags these errors, finding bugs, and generally improving the code quality. However, you have to compile and use your existing code, so the developers have worked very hard to allow such programs to compile, and to flag these incompatibilities with warning messages. Though changes in the language make it impossible to be completely compatible, this compiler is much more backward-compatible than earlier versions of C++ 3.0.


Recompiling Your Code

Run your code through the compiler. In the majority of cases, this results in anachronism warnings, indicating where the language has changed or compiler bugs have been eliminated. Examine the warnings carefully, since some may indicate undetected errors in your program. Other warnings reflect changes in the language and can be ignored until you change the program. Remove the warnings using guidelines in the following sections.


Incompatibilities: C++ 3.0 to 4.2

In some rare cases, the C++ 3.0 implementation differs from the specification in the C++ Annotated Reference Manual (ARM), or generates incorrect code. In these cases, discussed in this section, C++ 4.2 is incompatible with C++ 3.0, and you must modify your code.

Error: K&R-style function definitions are no longer allowed

C++ 3.0 issues warnings; C++ 4.2 issues errors.

Error: You cannot set _new_handler via an assignment

To set _new_handler, call set_new_handler() if you use your own new handler. By assigning to _new_handler, ld issues an error that _new_handler is undefined. Use set_new_handler() to set your own new handler.

Error: Multiple declarations for A

C++ 3.0 allows two arguments with the same name in function prototypes. For example



extern int foo (int a, int a);

C++ 4.2 does not allow this.

Error: Global operator new() is always used when there is no class version

Resolution of operator new() for nested classes in C++ 4.2 is different from C++ 3.0. C++ 3.0 erroneously uses the operator new() from the outer class in preference to the global operator new(), as specified in the ARM.

C++ 4.2 does not duplicate this bug, because to do so would change the semantics of correct programs. For example, the following test case gives different results when compiled with C++ 3.0 and C++4.2:



#include <stdio.h>
#include <stdlib.h>

class Foo {
public:
void *operator new(size_t sz);
class Bar {
public:
int j;
Bar(int i) {j = 1;};
};
};

void *Foo::operator new(size_t sz) {
printf("Hi!\n");
return ::operator new(sz);
}

int main () {
Foo::Bar *b = new Foo::Bar(17);
return 0;
}

C++ 3.0 execution produces "Hi!" while C++ 4.2 produces no output.

Solution: In the unlikely case that your program depends on this behavior, define Foo::Bar::operator new() and call Foo::operator new() from the new function.

Error: typedef names are not structure keys

C++ 3.0 and C++ 4.2 differ in the treatment of typedef names for structure types. C++ 3.0 treats the typedef name as a struct name. For example, you could write:

typedef struct { int x; } A;
struct A avar;

The DWP and ARM state that the second declaration declares a new structure name A. This is an error since there is already an existing typedef name A. The result is:

Error: Multiple declaration for A.
Error: The type A is incomplete.
These errors show up differently when there are local scopes involved, and interpreting the code the same way as C++ 3.0 can actually change the meaning of a legal program. The following code shows some of the confusion that may arise

typedef struct { int x; } A;
void bug () {
A ** ptpt;
typedef struct A* Xss; // Declares a local struct A
ptpt = (Xss*) new Xss[2]; // error here
*ptpt = (A*) new(A); // errors
}


The error messages look like this:

line 5: Error: Cannot assign A(local)** to A**.
line 6: Error: The type "A(local)" is incomplete.
line 6: Error: Cannot assign A(local)* to A*.

Solution: Use structure tags instead of typedef names. To leave the typedef name for C compatibility, add the structure name, and use it in both places

typedef struct A { int x; } A;


Error: Redefining AAAA after use in BBBB

C++ contains rules that prohibit any redefinition of an outer scope name that has been used in the class. For example

typedef int TI;
class C {
TI iv;
float TI;
};

or, using the same typedef


class D {
TI TI;
};

Both cases produce an error message:

Error: Redefining TI after use in C
Both cases are legal in C. C++ 3.0 does not detect this situation at all. C++ 4.2 always detects the situation, and for classes, where the usage could be disastrous, reports an error. For structs that use no member functions or other C++ features, the compiler gives a warning.

Solution: Change one of the names.

Error: Cannot assign int(*)(...) to int(*)(int, char).

C++ 3.0 has a bug that allows the assignment in the following program fragment:

int (*pfp)(int, char);
extern int foo(int, char);
void func() {
pfp = (int (*)(...))foo; // error
// pfp = (int (*)(int, char))foo; this works
}

This error is not detected in a direct cast as the right hand side of an assignment, and pointers of type int(*)(...) cannot be assigned to other pointers to functions. This bug does not exist in C++ 4.2.


Other Errors

Error: Cannot return int from a function which should return char*

The expression (anything, 0) is not a null-pointer constant. For example, the following program results in a compilation error:

int error();
char * foo() {
return (error(), 0); // error
// should be:
// return (error(),(char*) 0);
// or:
// error();
// return 0;
}

Solution: Cast zero to the appropriate pointer type, or to pull the constant zero out of the comma expression.

Error: Cannot use {} to initialize <class name>.

According to the ARM, it is illegal to initialize a class with a base class using the aggregate initialization syntax. C++ 3.0 used to allow this as long as there were no virtual functions and no constructors.

Solution: Write a constructor and initialize the class with that.


Warnings

Warnings reflect changes in the language or errors undetected by C++ 3.0. A few warnings reflect areas where the current language definition makes code illegal, but we believe this definition should be changed.

Warning: AAAA is not accessible from BBBB

There are several contexts in which this message can appear:

Solution: Make the constructor public.

Solution: Correct the access of the type or remove the reference.

Solution: Evaluate whether the type itself should be private. If so, you should see no other warnings about access to the type, and this warning can be ignored. Otherwise, make the type (though not necessarily the members) public. For example:


class A {
class B {
f();
    };
};
A::B::f() // warning here
{ //stuff
}

C++ 4.2 and the ARM do not allow this.

Solution: Make the enumerator public.

Solutions:

1. M ake Base::Base(int) public, or

2. Add `friend class Derived;' to the definition of class Base.

Warning: Default parameters are not allowed for AAAA

There are two cases that can cause this warning. The first is putting default parameters on overloaded operators. Such defaults are made illegal by the DWP, though C++ 3.0 allows them.

Solution: Remove the parameters from the operators. Since the only way the default parameters can be used is in an explicit call, this solution should cause no problem.

The second context is on pointers to functions. The ARM states that default parameters only apply to function declarations, not to pointers to functions. C++ 3.0 allows default parameters on such pointers, but its handling of them is inconsistent.

Solution: Remove defaults from function pointer declarations and update any calls that use them.

Warning: Formal argument AAAA of type BBBB has an inaccessible copy constructor

or

Warning: Formal argument AAAA of type BBBB in call to CCCC has an inaccessible copy constructor

These messages indicate that the object being passed as an argument cannot be copied, even though the compiler is able to eliminate the copy as an optimization. C++ 3.0 does not diagnose such errors, mostly because the language was not clarified on the situation until fairly recently.

Solution: Though the obvious solution is to make the copy constructor accessible, this may indicate an improper use of a class that was never intended to be copied. Check the program logic to determine the proper correction.

Warning: main() must have a return type of int

Though main() has always been required to return int, C++ 3.0 does not enforce this. Programs that return some other type may produce unpredictable results.

Solution: Change the definition of main() so it returns int.

Warning: The copy constructor for AAAA should take const AAAA&

or

Warning: The copy constructor for argument AAAA of type BBBB should take const BBBB&

or

Warning: The copy constructor for argument AAAA of type BBBB in call to CCCC should take const BBBB&

These warnings occur when the compiler has eliminated a copy constructor that would be illegal if called. C++ 3.0 detects this error when the copy constructor was actually used, but not when it was eliminated.

Solution: Since copy constructors that do not take const parameters are seldom desirable, the preferred solution is to modify the copy constructor.

Warning: Trailing comma in a parameter list

C++ 3.0 does not detect an erroneous trailing comma in an actual parameter list. For example, it allows

extern void f(int, int);
f(1, 2,)

Solution: Remove the extra comma.

Warning: Temporary created for argument AAAA

or

Warning: Temporary created for argument AAAA in call to BBBB

These warnings indicate the compiler created a temporary value for an argument that was a reference to a non-const type. For example:

extern void f(int&);
f(1); // called with a non-lvalue
This is always an error, but was accepted by earlier versions of C++. Even C++ 3.0 missed some cases, so this is a warning rather than a error.

Solution: The problem may be as simple as an inadvertently omitted const in the declaration, or there may be a program logic error.

Warning: Use of count in delete []

Earlier versions required an element count in the brackets of delete[]. C++ 4.2 allows this count, but ignores it.

Solution: Remove the count.


Type Warnings

Warning: AAAA was previously declared extern, not static

This is an error, and in most cases C++ 3.0 diagnosed this error correctly. The DWP states that any user-defined global version of operator new() or operator delete() is used by the library as well as the user's code. The functions must be global, so static versions are not allowed. This rule does not apply to placement versions of operator new(), only to the default version.

Warning: Assigning AAAA to the enum BBBB is obsolete

This anachronism is carried over from C++ 3.0. It is illegal to assign any value to an enumeration variable that is not of the enumerated type.

Solution: Change your program logic or cast the value to the enumerated type.

Warning: Attempt to redefine AAAA without using #undef

Macros cannot be redefined without an intervening #undef.

Solution: Insert #undef AAAA before redefining it.

Warning: Initialization without a class name is now obsolete

This warning is carried over directly from C++ 3.0. It occurs when writing a constructor for a derived class

class B {
B(int);
};
class D: public B {
D(int);
};
D::D(int i) : (i) {}
// ^warning here
{}

Solution: Name the base class directly in the constructor initializer, as follows;

D::D(int i) : B(i) {}

Warning: Cannot delete a pointer to a constant (AAAA)

C++ 3.0 does not detect this error. C++ 4.2 does, but gives you a warning.

Solution: Do not delete a pointer to a constant, as it is almost certainly an error.

Warning: Empty declaration (probably an extra semicolon)

Empty declarations are not allowed, though empty statements are. This is usually the result of an editing error or an incorrect macro invocation. C++ 3.0 does not detect such empty declarations, so this is only a warning.

Warning: Objects of type AAAA must be initialized

This warning is produced when you use new() to allocate a const object without providing an initial value or a default constructor, as shown in the following example:

const int * ip = new const int;

This is an error, since constants of unknown value are not useful. The solution is to add an initializer. The preceding example would then become

const int * ip = new const int(0);

Warning: Temporary used for non-const reference, now obsolete

Earlier versions of C++ allowed the initialization of a non-const reference with an incompatible type or non-lvalue. This is obsolete now, but causes a warning message. To avoid the warning, check your program logic, and if you want a temporary, make an explicit one. For example, convert

short sv;
int & ir = sv;

to

short sv;
short & ir = sv;

or

int irtemp = sv;
int & ir = irtemp;

Formal argument AAAA of type BBBB is being passed CCCC

or

Formal argument AAAA of type BBBB in call to CCCC is being passed DDDD

These warnings indicate that the conversion required to pass the argument is illegal, but that C++ 3.0 did not detect the illegality. Failure to handle const and volatile properly on pointers is a major cause of this problem. You can usually correct it with an explicit cast, but the error is probably the result of a logic error. Passing a value of type char** to a parameter of type const char** is illegal in both C++ and ANSI C. This is not an error or oversight in the standard as such assignments open a hole in the type system and violate const safety. It is legal in C++ to pass a value of type const char** to a parameter of type const char* const*.


Other Warnings

Warning: Undefined character escape sequence

The only string or character constant escape sequences which are allowed in C++ are:

Table  A-1 Escape Sequences 

newline

NL(LF)

\n

horizontal tab

HT

\t

vertical tab

VT

\v

backspace

BS

\b

carriage return

CR

\r

form feed

FF

\f

alert

BEL

\a

backslash

\

\\

question mark

?

\?

single quote

'

\'

double quote

"

\"

octal number

ooo

\ooo

hex number

hhh

\xhhh

The effect of any other escape sequence is undefined. C++ 4.2, like C++ 3.0, has replaced the entire escape sequence with the character following the backslash, which may or may not be what was intended.

Solution: Determine the intention of the code and substitute the correct character, possibly using a hex escape sequence.

Warning: Use AAAA:: for access to BBBB

Access to a nested type without an appropriate qualifier is allowed for compatibility with earlier versions of C++. Each such reference is flagged with this warning.

Solution: Use explicit qualification when using the nested type.

Warning: Using AAAA to initialize BBBB

C++ 3.0 was lax in its type checking, particularly when pointers to const were involved. Passing a value of type char** to a parameter of type const char** is illegal in both C++ and ANSI C. This is not an error or oversight in the standard as such assignments open a hole in the type system and violate const safety. It is legal in C++ to pass a value of type const char** to a parameter of type const char* const*.

Solution: Failure to handle const and volatile properly on pointers is a major cause of this problem. You can usually correct it with an explicit cast, but the error is probably the result of a logic error.

Warning: A declaration does not specify a tag or an identifier

ANSI C introduced the restriction that a declaration must define at least a tag or an identifier. The ARM is less precise, stating that a declaration introduces one or more names into a program. A declaration such as extern int; is useless and therefore flagged as an anachronism.

Solution: Eliminate the extraneous code.


Other Differences

Other differences between C++ 3.0 and C++ 4.2 follow.

operator = ()

C++ 3.0 accepts any operator=() taking any arguments as a legitimate assignment operator for a class. C++ 4.2 and the DWP accept declarations of the form X::operator=(X&).

Initializing Non-Aggregate Classes

C++ 3.0 allows the use of initializer lists with non-aggregate classes. This use is not allowed by the ARM (see the ARM, Section 8.4.1). C++ 4.2 enforces this rule. For example, the following is illegal:

class base {
public:
    const char *name;
unsigned int i1;
unsigned int i2;
unsigned int i3;
};

class foo : public base {
public:
    char c;
unsigned int i4;
};

static foo array[] = {
{"hello world", 0, 0, 0, 'c', 0}
};

Using the Same Names in Base and Derived Classes

C++ 3.0 allows an enumerator name defined in a base class to be used as a derived class name. The following test case compiles without errors with C++ 3.0, but not with C++ 4.2

class foo {
public:
   typedef enum {
	 bar,
	 foobar
   } footype;
};

class bar  :  public foo {
public:
  bar();
  ~bar();
  bar(const bar &b);			         // Error here
  bar &operator=(const bar &b); // Error here
};

You can disambiguate the name `bar' in the derived class by using the keyword class, as follows

class foo {
public:
  typedef enum {
    bar, 
    foobar
  } footype;
};
class bar : public foo {
public:
  bar();
  ~bar();
  bar(const class bar &b);
  class bar &operator=(const class bar &b);
};


Templates

If you are using templates with C++ 3.0, you may notice some differences when you move to C++ 4.2. C++ 3.0 generates (or instantiates) template functions when the program is being linked. A separate processor examines the object and library files, determines which template functions are needed, then uses the compiler to instantiate them. C++ 4.2 instantiates at compile time, generating those template instantiations needed by the module being compiled.

Link Order When Using Templates

The 4.0.1 compiler had an error in constructing the link line when templates were involved. In these cases, the old compiler would automatically place archives at the end of the supplied (and inserted template) object files. This could have unknown consequences when link order was important. The new compiler leaves the link order exactly as supplied, and only inserts template object files before the first non-object file (such as archives or shared library).

Specialization Registration

A specialization of a template is a user-defined version of a template that is normally generated by the compilation system. For example, for the template function:

template <class T> T foo ( T data );

A specialized version is:

int foo ( int data );

The compiler cannot differentiate between the declaration of a normal function and a template function. As a result, a special file, the options file, is available so that these specializations can be registered with the compiler. This options file resides in the template database, and contains many options that can determine how templates are generated. The options used to register specializations look like this for the above code fragment:

special foo(int);

The information needed to properly handle specializations of templates is covered in depth in the C++ User's Guide.

Template Repositories

Generated templates and their supporting files are stored in a directory, the template database. Except for the options file, all the files in the database are object files and state information files, maintained by the compiler. The difference between using the template database in C++ 4.2 versus C++ 3.0 is: when you use the -ptr option to specify the template database path, the path includes the database, named Templates.DB. For example:

In C++ 3.0:

-ptrMyDatabase
corresponds to a database located in ./MyDatabase.

In C++ 4.2:

-ptrMyDatabase
corresponds to a database located in ./MyDatabase/Templates.DB.

Central Database

You can use a central database to store generated templates. Do this by using the -ptr command-line directive to specify the location of your database. The inherent problem with a central database is that dependencies, types, and environmental data can change between executables sharing a common template and template database. Changes can lead to confusion, strange behavior at runtime, and missing data in the database. Template objects and dependencies in the relevant state-information files are based on template and type names. Because of potential conflicts between targets and violations of the one-definition rule, using templates across multiple targets may lead to unexpected behavior.

Multiple Databases

The template sources used during instantiation must be locatable from the directory where the referencing module is compiled. Use multiple databases by specifying multiple -ptr options on the command line. The first -ptr option is the writable template database. Whenever multiple databases are involved, specify -ptr as the first -ptr option. See the C++ User's Guide for details.

It is recommended that you not use multiple -ptr options on the command line when using templates. Although this should work with the current version of the compiler, it is not guaranteed to work in future releases.


Placing Objects in Shared Memory

Placing objects with virtual functions into shared memory requires that the virtual tables needed by those objects be at the same virtual address in all tasks that refer to the objects. To achieve this, control virtual table generation using the +e0 and +e1 command-line flags. +e0 prevents generation of virtual tables. +e1 generates virtual tables for every class defined in that compilation unit. Follow these steps:

1. Create a file containing only class definitions.

2. Compile the file with +e1, generating an object file containing only virtual tables.

3. Place the object file at the appropriate spot in virtual memory.

In C++ 4.2, the exception-handling code generates some internal class objects, so the compilation must include -noex as well as +e1.

For example, assume that you have header files type1.h and type2.h, and that all classes used within the program are defined in one of those files. You can compile most of the program using:

CC -c +e0 a.cc b.cc ...

and create a file vt.cc containing:

 #include "type1.h"
#include "type2.h"

and compile it with

CC -c +e1 -noex vt.cc

The file vt.o contains the virtual tables needed by the program.

If you want to generate the virtual tables for the exception data structures, omit the -noex option on the CC command line.




Previous Next Contents Index Doc Set Home