web-dev-qa-db-fra.com

Installer std :: vector dans le constructeur de classe

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.

23
fenkerbb

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.

32
Luchian Grigore

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.

11
Baltasarq
#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  
2
Scourge