Langages avec “copie par défaut”
En C, mais aussi en C++, une affectation est une copie.
Rappel du C
Le C est un langage qui fait une copie
struct Point {
int x;
int y;
}
int main() {
Point p = {.x = 3, .y = 2};
Point q = p;
q.x = 100;
}
Que vaut p.x ?
En C++ pareil, on copie
vector<int> A = ...; // un vecteur de 10000000 d'éléments
vector<int> B = A;
Oui, oui, … l’affectation B = A; prend beeeaaaaucoup de temps. Elle réalise une copie du vecteur et des éléments qui le contient.
Attention : Python, Java, Javascript
Attention, dans des langages comme Python, Java, Javascript, les objets ne sont pas copiés car chaque variable en réalité est un pointeur. C’est uniquement le pointeur qui est copié.
- Que fait ce programme Java ?
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
ArrayList<String> listcars = cars;
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
System.out.println(listcars);
}
}
Dans le programme, cars et listcars pointe vers la même ArrayList. Donc le programme imprime la liste des 4 voitures.
Constructeurs
Constructeur
class Point {
public:
int x;
int y;
}
int main() {
Point p;
}
Que vaut p.x ?
p.x n’a pas été initialisé. Donc il vaut juste ce qu’il y avait à cet endroit dans la mémoire.
On peut créer un constructeur par défaut, sans paramètre.
class Point {
public:
int x;
int y;
Point() {
x = 0;
y = 0;
}
}
int main() {
Point p;
}
Ou alors mettre des paramètres :
class Point {
public:
int x;
int y;
Point(int ax, int ay) {
x = ax;
y = ay;
}
}
int main() {
Point p(5, 2);
}
Constructeur par copie
En C++, la copie a lieu comme en C :
- quand on réalise une affectation
- quand on passe une valeur en paramètre à une fonction.
Par défaut, quand C++ fait une “copie”, il “copie” les champs. Si vous voulez personnaliser comment fonctionne la copie, C++ en offre la possibilité avec un constructeur par copie. Un constructeur par copie prend en argument une référence vers un objet du même type. Par exemple :
class BigInt {
BigInt(BigInt& x) {
// là on écrit le code qui copie
}
}
C’est le constructeur appelé si on fait :
BigInt x = ...
BigInt y = x; // ici on appelle le constructeur par copie
Exercices
#include <iostream>
#include <vector>
class A {
public:
std::vector<int> p;
};
int main()
{
A a;
A b = a;
a.p.push_back(5);
std::cout << a.p.size() << std::endl;
std::cout << b.p.size() << std::endl;
return 0;
}
La ligne A a; crée un objet de type A. Puis A b = a; réalise une copie. Alors que a.p.push_back(5); ajoute 5 au vecteur a.p, le vecteur b.p est différent et reste vide. Donc le programme écrit 1 puis 0.