Je conçois une classe qui a un std::vector<int>
comme variable d'instance. J'utilise un std::vector
car je dois définir sa taille au moment de l'exécution. Voici les parties pertinentes de mon code:
my_class.h:
#include <vector>
using std::vector;
class MyClass {
int size;
vector<int> vec;
}
my_class.cc:
#include "my_class.h"
using std::vector
MyClass::MyClass(int m_size) : size(m_size) {
vec = new vector<int>(size,0);
}
Lorsque j'essaie de compiler, j'obtiens ces messages d'erreur:
g++ -c -Wall my_class.cc -o my_class.o
my_class.cc: In constructor ‘MyClass::MyClass(int):
my_class.cc:4 error: no match for ‘operator=’ in ‘((MyClass*)this)->My_Class::vec = ((*(const allocator_type*)(& std::allocator<int>())), (operator new(24u), (<statement>, ((std::vector<int>*)<anonymous>))))’
make: *** [my_class.o] Error 1
Cependant, lorsque je change la ligne incriminée en:
vector<int> temp(size,0);
vec = temp;
Il se compile maintenant sans accroc et j'obtiens le comportement souhaité et je peux accéder à mon vecteur comme
vec[i] // i having been defined as an int yada yada yada
Cette solution de contournement est correcte, mais je voudrais comprendre pourquoi cela fonctionne et la première méthode échoue. Merci d'avance.
Faites juste:
MyClass::MyClass(int m_size) : size(m_size), vec(m_size, 0)
Vous semblez déjà connaître les listes d'initialisation, pourquoi ne pas y initialiser directement le vecteur?
vec = new vector<int>(size,0);
est illégal car new
renvoie un pointeur et dans votre cas vec
est un objet.
Votre deuxième option:
vector<int> temp(size,0);
vec = temp;
bien qu'il compile, fait un travail supplémentaire sans aucun gain. Au moment où vous atteignez l'affectation, deux vecteurs auraient déjà été construits et supprimés par la suite.
L'utilisation du vecteur est légale dans votre classe, le problème est de savoir comment l'initialiser:
#include <vector>
class MyClass {
public:
MyClass(int m_size);
// ... more things...
private:
int size;
vector<int> vec;
}
Vous affectez un pointeur à un nouvel objet vectoriel, comme si cet objet vectoriel n'était pas initialisé.
vec = new vector<int>(size,0);
Si vous voulez vraiment que cela fonctionne, vous devez déclarer votre objet vec
comme:
vector<int> * vec;
Et n'oubliez pas d'ajouter un destructeur:
MyClass::~MyClass {
delete vec;
}
Pourquoi cela a-t-il fonctionné lorsque vous avez supprimé la particule new
? Parce que vous créez un nouvel objet vector
, et écrasement celui de votre classe (cela ne garantit cependant pas que l'original soit correctement éliminé).
En fait, vous n'avez pas besoin de faire ça. Votre objet vector
est déjà initialisé (son constructeur par défaut appelé) lorsque vous avez atteint le constructeur de MyClass. Si vous voulez simplement être sûr que la mémoire est réservée aux éléments size
:
MyClass::MyClass(int m_size): size(m_size) {
vec.reserve( size );
}
Si vous voulez que votre vecteur ait des éléments size
, alors:
MyClass::MyClass(int m_size): size(m_size), vec(m_size, 0)
{}
Enfin, comme le souligne l'un des commentateurs, la taille n'est pas réellement nécessaire une fois le vecteur construit. Vous pouvez donc vous débarrasser du membre size
:
class MyClass {
public:
MyClass(int m_size): vec(m_size, 0)
{}
unsigned int getSize() const
{ return vec.size(); }
// ... more things...
private:
vector<int> vec;
}
J'espère que cela t'aides.
#include <vector>
#include <iostream>
#include <string>
#include <typeinfo>
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::to_string;
class Parse
{
private:
string m_str;
vector<string> m_vec;
public:
// Constructor with all defaults (1 of 4 constructors)
Parse(){
cout << "\ncreating class with all default values\n";
m_str = "";
m_vec.Push_back("");
}
// Constructor with all cases used
Parse (string &tmp_str,
vector<string> tmp_vec):
m_str (tmp_str),
m_vec (tmp_vec)
{
cout << "Your vector contains " + to_string(m_str.size()) + " arguments\n";
}
// Constructor with other contents given but not vector
Parse (string &tmp_str):
m_str (tmp_str)
{
m_vec.Push_back("");
}
// Constructor with only Vector given but not other contents
Parse (vector<string> tmp_vec):
m_vec (tmp_vec)
{
m_str = "";
}
string get_str_var(){return m_str;}
void classed_print_vector_strings()
{
for (string i : m_vec){ cout << i << " \n";}
}
};
// rm ./class_vector; g++ class_vector.cpp -o class_vector -std=c++17; ./class_vector arg1 arg2 arg3
int main(int argc, char *argv[])
{
// turn **argv to a vector
vector<string> args(argv, argv + argc);
// iterate from argv through argv+argc
// initialize with default arguments.
Parse tracker1;
// initalize with all used arguments
Parse tracker2(args[0], args);
// initalize with only the vector
Parse tracker3(args);
// initalzie without the vector, but with another arg
Parse tracker4(args[0]);
cout << "\nTracker 1 ---------------------\n";
tracker1.classed_print_vector_strings();
cout << "\nTracker 2 ---------------------\n";
tracker2.classed_print_vector_strings();
cout << "\nTracker 3 ---------------------\n";
tracker3.classed_print_vector_strings();
cout << "\nTracker 4 ---------------------\n";
tracker4.classed_print_vector_strings();
return 0;
}
// rm ./class_vector; g++ class_vector.cpp -o class_vector -std=c++17; ./class_vector arg1 arg2 arg3
// This will show you how to create a class that will give
// you the option to initilize the class with or without
// the vector with other arguments present and/or not present.
// My Background. . .
// github.com/Radicalware
// Radicalware.net
// https://www.youtube.com/channel/UCivwmYxoOdDT3GmDnD0CfQA/playlists