Undefined Behavior ?

Le problème exposé dans ce sujet a été résolu.

Bonjour,

voici un exemple venant de cplusplus.com:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// example: one class, two objects
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    void set_values (int,int);
    int area () {return width*height;}
};

void Rectangle::set_values (int x, int y) {
  width = x;
  height = y;
}

int main () {
  Rectangle rect, rectb;
  rect.set_values (3,4);
  rectb.set_values (5,6);
  cout << "rect area: " << rect.area() << endl;
  cout << "rectb area: " << rectb.area() << endl;
  return 0;
}

On nous dit que sans appel à set_values() on a le droit à un UB parce que width et height ne sont pas défini (ce qui est vrai pour avoir testé :) ) Pourtant je pensais qu'il y avait alors un constructeur par défaut et que width et height se retrouvaient alors initialisés par défaut à 0. Où est l'erreur ?

Salut,

Un constructeur par défaut se contente d'appeler les "constructeurs par défaut" de chaque attribut de la classe. Cependant, pour les types natifs (bool, int, float, double, …), le "constructeur par défaut" (entre guillemets car je ne suis pas sûr que l'on puisse appeler cela comme ça pour les types natifs) ne définit pas de valeur. Ainsi :

1
int a;

a peut avoir n'importe quelle valeur de ce qu'il y avait à son emplacement mémoire.

+0 -0

Bonjour, Ton constructeur par défaut est le suivant :

1
2
3
4
5
6
7
8
9
class Rectangle {
public :
    Rectangle();
private :
    int width;
    int height;
};

Rectangle::Rectangle() : {}

Il ne fait rien, il se contente juste de créer l'objet sans initialiser aucun de ses attributs, seul un emplacement mémoire leur est réservé mais il est laissé tel qu'il était avant. Si tu veux initialiser tes variables avec une valeur par défaut, il faut que tu surcharges ton constructeur de la manière suivant :

1
2
3
4
5
6
7
8
9
class Rectangle {
public :
    Rectangle(int widthInit = 0, int heightInit = 0);
private :
    int width;
    int height;
};

Rectangle::Rectangle(int widthInit, int heightInit) : width(widthInit), height(heightInit) {}
+0 -0

Normalement le constructeur par défaut assigne les cases mémoires mais à aucun moment il ne donnent de valeur.

Si j'écris ce code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>


using std::cout;
using std::cerr;
using std::cin;
using std::endl;


int main()
{
    int i;
    i = 0;
    cout << i << endl;
    int j;
    cout << j << endl;

    return 0;
}

Et que je compile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# ludovic @ Tardis in /home/ludovic/workspace/C++/bordel [14:42:43] 
$ make
g++ -std=c++14 -W -Wall -Wextra -c main.cpp -o main.o
main.cpp: Dans la fonction ‘int main()’:
main.cpp:17:13: attention : ‘j’ is used uninitialized in this function [-Wuninitialized]
     cout << j << endl;
             ^
g++ -std=c++14 -W -Wall -Wextra main.o -o executable

# ludovic @ Tardis in /home/ludovic/workspace/C++/bordel [14:42:48] 
$ ./executable 
0
0

le compilateur me dit bien que j n'est pas initialisé.

Par contre le programme s’exécute quand même et ça je ne sais pas pourquoi.

Edit: je me suis fais devancer ;_;

+0 -0

@LudoBike, Il s'exécute car le fait de ne pas initialiser une variable peut-être voulu par le développeur et donc le compilateur met juste un warning, il ne considère pas cela comme une erreur (bien que dans l'exemple que tu as donné cela en soit une), c'est au développeur de faire attention à ce que ses variables soit dans un état viable avant de les utiliser.

@Matthieuj, oui uniquement si tu as surchargé le constructeur comme je l'ai dis parce que le compilateur va faire appel au constructeur surchargé plutôt que au constructeur par défaut. Si tu ne surcharges pas le constructeur, les membres de ton objet ne seront pas initialisés.

Au passage on préfère initialisé un objet de cette manière :

1
2
Rectangle a{2, 3};
Rectangle b;  //si tu ne passes pas d'arguments au constructeur, il vaut mieux enlever les crochets

plutôt que de cette manière :

1
Rectangle c = Rectangle();
+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte