Partage
  • Partager sur Facebook
  • Partager sur Twitter

gros problème de tbleau

Sujet résolu
4 juin 2020 à 14:29:04

bonjour j'ai creer une classe
class Arme {
    private:
        string name;
        int damage;
};

et je souhaite creer un tableau

array<Arme, 3> weapns;

mais je ne sais pas comment instantier les deux attributs de chaque objet de mon tableau comme cela

array<Arme,3> weapns = {"epee" \ 10, "arc" \ 5};

c'est un exemple qui ne fonctionne pas et je ne sait pas comment faire pour que cela marche.

merci de vos réponses


-
Edité par TidianDelage1 4 juin 2020 à 14:29:14

  • Partager sur Facebook
  • Partager sur Twitter
4 juin 2020 à 14:39:41

= { {"chaine", nombre}, ...};

  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
Anonyme
4 juin 2020 à 15:03:32

Il faudrait un constructeur aussi en fait.
  • Partager sur Facebook
  • Partager sur Twitter
5 juin 2020 à 0:19:21

Bonsoir,

AntiXeon a écrit:

Il faudrait un constructeur aussi en fait.

EDIT : cf le petit message à la fin, la remarque d'AntiXeon est complètement juste, je me suis abominablement planté quand j'ai rédigé ce qui suit. Je le laisse cependant reste parce que ça pourrait peut-être servir à quelqu'un un jour sur certains principes.


Chaque classe ou structure est initialisée avec un constructeur par défaut. D'ailleurs, ici, l'intérêt de la classe reste à démontrer puisqu'il n'y a pas l'air d'y avoir un invariant à maintenir (en l'état il n'y a même aucun moyen d'accéder aux données contenues). L'usage d'une structure pourrait s'avérer plus pertinente (selon le contexte).

A ma connaissance, la seule différence entre une classe et une structure est que les membres d'une structures sont par défaut publiques alors que ceux d'une classe sont privés.

Pour revenir au constructeur, ce qu'a proposé lmghs est simplement un appel au constructeur par défaut, qui pourrait être explicité par "={ Arme{"chaine", nombre}, ...};"

Ce qui nous permet d'ailleurs de conclure que le constructeur par défaut a certainement à peu près cette tête là :

Arme(std::string iname,int idamage) : name{std::move(iname)},damage{std::move(idamage)}
{}

Il est d'ailleurs d'usage pour des variables membres d'une structure (struct ou class) d'expliciter leur appartenance avec un symbole commun, le plus courant est peut-être de préfixer chaque variable membre par "m_" ce qui donnerait pour la définition de la class

class Arme {
    private:
        string m_name;
        int m_damage;
};

ou les suffixer par un "_" ou n'importe quel autre moyen du style.

EDIT :

Je me suis trompé, nous avons ici besoin d'un constructeur définis par l'utilisateur (comme celui que j'ai écris plus haut) puisque les données sont privées. Désolé de l'erreur.

-
Edité par Cypher__ 5 juin 2020 à 1:30:15

  • Partager sur Facebook
  • Partager sur Twitter
5 juin 2020 à 0:42:55

Un constructeur par défaut n'est-il pas un constructeur que l'on peu appeler sans paramètres ?
  • Partager sur Facebook
  • Partager sur Twitter
5 juin 2020 à 0:59:56

rouloude a écrit:

Un constructeur par défaut n'est-il pas un constructeur que l'on peu appeler sans paramètres ?


Si. D'ailleurs le compilateur crée bien un constructeur par défaut (dans le vrai sens du terme) aussi, on peut parfaitement, et dans le cas donné ici nous sommes obligés d'ailleurs, initialiser la variable par

Arme a{};

Même si j'admets que dans ce que j'ai écris, le vrai sens serait plutôt : constructeur créé automatiquement par le compilateur.

Mais imaginons que les attributs aient étés publiques (cas d'une structure typiquement) donc que la définition de Arme soit la suivante :

struct Arme
{
    std::string m_name;
    int m_damage;
};

On pourrait alors parfaitement initialiser des variables Arme comme ceci

Arme a0{}; //Attention, les variables membre contiennent des valeurs inconnues

Arme a1{"Épée"};//Attention, valeur de m_damage inconnue

Arme a2{"Lance",10};//Toutes les valeurs spécifiées


Alors qu'aucun constructeur n'a été défini par le programmeur.

  • Partager sur Facebook
  • Partager sur Twitter
5 juin 2020 à 2:01:54

Cypher__ a écrit:

Arme a0{}; //Attention, les variables membre contiennent des valeurs inconnues

Arme a1{"Épée"};//Attention, valeur de m_damage inconnue

Arme a2{"Lance",10};//Toutes les valeurs spécifiées

D'où l'intérêt de d'initialiser les données membres dans la déclaration de la structure de données ? Pour éviter les valeurs indéfinies ont devrait faire:

#include <string>

struct Weapon {
  std::string name {}; // Initialisation par défaut
  unsigned int damage { 0 };
};

int main() {
  Weapon default_weapon {};
  // Pas de valeur indéfinie.
}

 A priori ça devrait pas poser problème de faire ainsi... Dites-moi ce que vous en pensez.

=====

D'ailleurs, est-ce que le compilateur propose une "sécurité" pour les variables déclarées sans être initialisées ? J'ai fais des petits tests, je compile avec clang++ version 10.0.1 (-Wall).

Pour une variable de type int non-initialisée mais utilisée:

/home/devio/C++/Random/sources/main.cpp:8:15: warning: variable 'test' is uninitialized when used here [-Wuninitialized]
        std::cout << test << std::endl;
                     ^~~~
/home/devio/C++/Random/sources/main.cpp:7:10: note: initialize the variable 'test' to silence this warning
        int test;
                ^
                 = 0
1 warning generated.

Par contre ma variable a bien été initialisée avec 0.

Pour une chaine de caractères type C c'est la même histoire (avertissement quand j'essaie d'utiliser la valeur pointée et erreur de segmentation lors de l'exécution). Le pointeur sur char pointe sur une adresse invalide (0x0).

Du coup ma question c'est: Est-ce le compilateur qui se charge de réparer ce genre de petites bétises ? Ou ça nécessite un procédé complètement différent ?

-
Edité par Daimyo_ 5 juin 2020 à 2:19:30

  • Partager sur Facebook
  • Partager sur Twitter
5 juin 2020 à 11:35:20

> Par contre ma variable a bien été initialisée avec 0.

Hum? Tu parles de "int i; cout << i"? Alors non. La variable est dans un état non défini ou non spécifié, je ne sais plus. 0 est un hasard et/ou un choix de ton compilateur dans le mode de compilation que tu as choisi.

En faire une erreur de compilation devrait être le standard. Sauf qu'il y a trop de vieux codes qui faisaient ça en espérant randomniser l'état de la variable, ou d'autres qui supposent que la variable sera 0-initialisée, merci le mode debug de VC++. C'est sans compter les dernières générations de compilos qui s’octroient les droits qui sont leurs: faire ce qu'ils veulent de l'état de la variable.

Bref, utiliser une variable non initialisée c'est mal. Pour une chose qui est très certainement une entité comme ici, je serai tenté d'interdire le constructeur par défaut -- il n'y a que les flux qui peuvent me faire hésiter. Sa génération par défaut se bloque en définissant n'importe quel autre constructeur.

  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
5 juin 2020 à 11:47:06

Le sens de constructeur par défaut, c'est pour parler du constructeur qui est appelé quand on n'en cite aucun. Ce qui correspond au constructeur sans paramêtre.


Exemple, la déclaration  std::string chaine[10];  demande l'appel du constructeur par défaut  de string pour créer le premier élement (et si je me rappelle bien du constructeur de copie pour fabriquer les autres à partir du premier, encore que ça ait l'air de dépendre des versions, haha, sont-ils farceurs dans le comité de normalisation).

Le constructeur qui se définit tout seul quand on ne déclare pas de constructeur, ça porte un autre nom : constructeur par défaut déclaré implicitement.

Extrait d'un brouillon de norme C++ (en 2005), 12.1 constructors :

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf

Pour répondre à la question, comment initialiser un Array avec des instances construites:

	std::array<Arme, 3> armes {
		Arme { "polochon",           33},
		Arme { "édredon percé",      12},
		Arme { "chaussette qui pue", 200}
	};



-
Edité par michelbillaud 5 juin 2020 à 12:13:29

  • Partager sur Facebook
  • Partager sur Twitter
5 juin 2020 à 14:59:41

>que la variable sera 0-initialisée, merci le mode debug de VC++

MSVC utilise 0xCDCD ou des motifs approchants (en fonction du mode d'allocation : pile, tas) et pas 0.

Alors, oui, on peut dire merci à MSVC, et sans ironie. ;)

  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
5 juin 2020 à 15:32:58

> MSVC utilise 0xCDCD ou des motifs approchants (en fonction du mode d'allocation : pile, tas) et pas 0.

Désolé, j'en suis resté à la version 6 ^^'. C'est bien qu'ils aient changé leur mode debug.

  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
5 juin 2020 à 17:05:07

C'était déjà le cas en version 6, je crois. J'ai assez peu utilisé les versions 5 et antérieurs.
  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
5 juin 2020 à 21:53:32

> Arme a0{}; //Attention, les variables membres contiennent des valeurs inconnues

En absence de constructeur, c'est une zero-initialization, les valeurs sont donc parfaitement connues.

Pour avoir des valeurs inconnues, il faudrait faire Arme a0;, mais cela ne s'appliquerait que pour m_damage, car m_name à un constructeur par défaut.

Clang à une option pour initialiser les variables qui ne sont pas initialisées: -ftrivial-auto-var-init=pattern qui met tous les octets à 0xAA.

Des fois je préfère avoir des variables non-initialisées, car je trouve plus pertinent d'avoir un avertissement parce qu'on zappe une branche plutôt qu'avoir une mauvaise valeur qui pourrait faire fonctionner le code. Ce qui m’embête est de ne pas pouvoir rendre explicite ce comportement. (J'ai vu une proposition pas mal dans ce sens: T x = void; + interdiction de ne pas initialiser implicitement).

  • Partager sur Facebook
  • Partager sur Twitter
5 juin 2020 à 23:04:57

> Des fois je préfère avoir des variables non-initialisées, car je trouve plus pertinent d'avoir un avertissement parce qu'on zappe une branche plutôt qu'avoir une mauvaise valeur qui pourrait faire fonctionner le code.

C'est pour ça que je préfère déclarer mes variables au dernier moment, à l'endroit où je peux généralement leur donner une valeur qui a un sens. L'idée de tout déclarer au début et de tout initialiser a zero "comme ça y a pas n'importe quoi dedans" m'a toujours paru remarquablement stupide.

Shit happens. Je préfère que le compilo puisse me signaler que je suis en train de faire une connerie avec une variable que j'ai oublié d'initialiser.

  • Partager sur Facebook
  • Partager sur Twitter
6 juin 2020 à 12:46:02

"-ftrivial-auto-var-init=pattern" peut être utile quand on récupère du vieux code et que les warning nous submergent, non ?
  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
6 juin 2020 à 13:27:22

Est-ce bien raisonnable, de faire une grosse impasse sur la vérification / correction de warnings quand on reprend du code ?

  • Partager sur Facebook
  • Partager sur Twitter
6 juin 2020 à 17:12:13

Je le vois plus comme un outil pour "randomiser" les valeurs qui ont tendance à être 0. Comme justification que j'ai vu passer, il y a aussi une volonté de cacher les valeurs précédentes en supposant qu'on puisse lire des données qui ne sont pas initialisées, donc plus une sécurité.

Cette option n'influence absolument les avertissements du compilateur qu'on peut de toute manière désactiver individuellement. Mais par contre, les outils runtime du genre valgrind qui vérifie la mémoire ne diront plus rien. Perso, pour valgrind, je trouve largement préférable de créer un fichier qui liste les erreurs à ignorer plutôt que de tout ignorer, surtout que dans un premier temps, on peut lui demander de créer le fichier pour nous.

  • Partager sur Facebook
  • Partager sur Twitter