Tests effectués sur le compilateur g++

projet GNU Egcs-1.1.2 release

© D. Mathieu     mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique
Créé le 04/08/2000 - Dernière mise à jour : 22/08/2000

Sommaire

Syntaxe et sémantique C++
opérateur ++ préfixé
Affectation des tableaux
Dimensions des tableaux
Modification des constantes
Bibliothèques standard (STL)
Exceptions
Exception length_error levée par la classe string
Exception out_of_range levée par la classe string
Exception length_error levée par la classe vector
 

Syntaxe et sémantique C++

opérateur ++ préfixé

    Les instructions suivantes donnaient un résultat faux dans la version précédente du compilateur :
 
     void Ess_01 (void)
    {
        int i;
        cout << "\nTest de preincrementation OK si valeurs egales\n\n";
        i = 0;
        cout << "1 = " <<       ++i << endl;
        i = 0;
        cout << "2 = " <<     ++++i << endl;
        i = 0;
        cout << "3 = " <<   ++++++i << endl;
        i = 0;
        cout << "4 = " << ++++++++i << endl;
        cout << endl;

    } // Ess_01()


Sommaire

Affectation des tableaux

    Selon la norme C++, l'affectation d'un tableau dans un autre n'est pas autorisée. En effet, l'identificateur d'un tableau représente l'adresse à laquelle le tableau est stocké en mémoire. C'est une constante, donc ne devrait pas être utilisée en tant que l-value (à gauche d'une affectation). Dans l'exemple ci-dessous, l'instruction [1] devrait donc être interdite à la compilation, ce qui n'est pas le cas.

    Le compilateur g++ projet GNU Egcs-1.1.2 release ne traite pas non plus Tab1 et Tab2 comme des pointeurs vers des vecteurs, car la modification d'un des deux tableaux ne modifie pas le contenu de l'autre (lignes [2] et [3]).

    Cependant, ce compilateur n'accepte que des affectations de tableaux "de même type" : il considère que Tab1 et Tab2 sont tous deux de type char [4]. Les affectations de deux tableaux de tailles différentes sont interdites (lignes [4] et [5]). Il en est de même pour le cas particulier des tableaux de caractères (ligne [6]).
 
    void Ess_02 (void)
    {
        cout << "\nTest d'affectation de tableau OK"
                " si erreur de compilation\n\n";

        char Tab1 [] = {'a', 'b', 'c', '\0'};
        char Tab2 [] = {'A', 'B', 'C', 0   };

        Tab1 = Tab2; // devrait générer une erreur de compil.    [1]

        Tab1 [1] = '1';                                     //   [2]
        Tab2 [1] = '2';                                     //   [3]

        cout << "Tab1 = " << Tab1 << endl;
        cout << "Tab2 = " << Tab2 << endl;

        cout << "Si Tab1 == Tab2, ils désignent le même objet, \n"
             << "  sinon, les tableaux ont été dupliqués par l'affectation\n\n";
 

        char Tab3 [] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\0'};

        // Tab3 = Tab1; // génère une erreur de compil.     //   [4]
        // Tab1 = Tab3; // génère une erreur de compil.     //   [5]

        char Libel1 [] = "bac";
        Libel1 = "car";     // autorisé 
        // Libel1 = "char"; // génère une erreur de compil. //   [6]

    } // Ess_02()


Sommaire

Dimensions des tableaux

    La norme C++ précise que les dimensions des tableaux doivent être des expressions entières :
"In several places, C++ requires expressions that evaluate to an integral or enumeration constant : as array bounds ...

constant­expression :
                conditional­expression

An integral constant­expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non­type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function­call, or comma operators shall not be used."

    Contrairement aux recommandations de la norme ci-dessus, le compilateur g++ projet GNU Egcs-1.1.2 release autorise la définition de tableau dont la taille n'est pas une constante, comme par exemple :
 
    void Ess_03 (void)
    {
        cout << "\nTest de definition de tableau de taille non constante\n\n";

        int i;

        cout << "Tapez un entier positif : ";
        cin >> i;

        char   Tab1 [i];                     // devrait générer une erreur de compil.
        char   Tab2 [strlen ("une chaine")]; // devrait générer une erreur de compil.

    } // Ess_03()


Sommaire

Modification des constantes

    Une fonction recevant en paramètre la référence d'un objet const, ne devrait pas pouvoir la renvoyer comme valeur de retour sans le qualifieur const. Le compilateur g++ projet GNU Egcs-1.1.2 release n'effectue cependant pas toutes les validations nécessaires, et laisse passer la séquence suvante :
 
    struct CBidon
    {
        int m_i;
        CBidon (const int i = 0) : m_i (i) {}
        bool operator < (const CBidon & Bidon) const
        {
            return m_i < Bidon.m_i;
        }
    }; // CBidon

    template <class T> T& Min (const T& a, const T& b)
    { return (a < b) ? a : b; }

    void f (void)
    {
        cout << "\nTest d'affectation de tableau OK"
                " si erreur de compilation\n\n";

        const CBidon CB1 (1);
        const CBidon CB2 (2);

        Min (CB1, CB2) = CBidon (4);  // [1]
                                                  // affichage : 

        cout << "CB1.m_i = " << CB1.m_i << '\n'   // CB1.m_i = 4
             << "CB2.m_i = " << CB2.m_i << endl;  // CB2.m_i = 2

    } // f()

    L'instruction [1] permet de modifier la constante CB1, comme le prouve l'affichage !!!
 
Sommaire

Bibliothèques standard (STL)

Exceptions

Exception length_error levée par la classe string

    Pour la fonction reserve() par exemple, de profil :
 
void reserve(size_type res_arg = 0);

la norme indique : "Throws: length_error if res_arg > max_size())"

    Malheureusement, la fonction reserve() n'est pas implémentée (voir fichier <g++2-/std/bastring.h>) :
 
void reserve (size_type) { }

    Pour le constructeur de profil :
 
basic_string (size_type n, charT c, const Allocator& a = Allocator());

la norme indique : "Throws: length_error if n == npos". A l'exécution, le programme indique le message "Segmentation fault", affiché avant que l'exception ait pu être levée (probablement au niveau de l'allocateur)

    En revanche, la fonction membre resize() lève correctement l'exception attendue.
 
void f (void)
{
    cout << "\nTest de l'exception length_error dans la classe string\n\n";
 
    try
    {
       string s;
       s.resize (s.max_size() + 1);
    }
    catch (length_error & exc)
    {
        cerr << "exception length_error capturée; "
            << exc.what() << endl;
    }

} // f()


Sommaire

Exception out_of_range levée par la classe string

    Correctement levée par exemple par la fonction at() en cas d'indice invalide.
 
void f (void)
{
    cout << "\nTest de l'exception out_of_range dans la classe string\n\n";
 
    try
    {
       string s ("Coucou");
       cout << s.at (8);
    }
    catch (out_of_range & exc)
    {
       cerr << "exception out_of_range capturée; "
            << exc.what() << endl;
    }

}// f()


Sommaire

Exception length_error levée par la classe vector

    La fonction reserve() de la classe vector est correctement implémentée dans le compilateur g++ projet GNU Egcs-1.1.2 release.
 
void f (void)
{
    cout << "\nTest de l'exception length_error dans la classe vector\n\n";
 
    try
    {
        vector <int> v;
        v.reserve (v.max_size() + 1);
    }
    catch (length_error & exc)
    {
        cerr << "exception length_error capturée; "
             << exc.what() << endl;
    }

} // f()

    Cependant, à l'exécution, le programme indique le message "Segmentation fault", affiché avant que l'exception ait pu être levée (probablement au niveau de l'allocateur) : ce n'est donc pas dû au compilateur C++.

Remarque : selon la norme, et contrairement à la classe string, la fonction reserve() est la seule à pouvoir lever cette exception pour la classe vector. La fonction resize() par exemple n'est pas censée lever d'exception. La norme ajoute en note :

"reserve() uses Allocator::allocate() which may throw an appropriate exception."

Sommaire

© D. Mathieu     mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique