2012-07-10 20 views
12

Estoy diseñando una clase que tiene un std::vector<int> como variable de instancia. Estoy usando un std::vector porque necesito establecer su tamaño en tiempo de ejecución. Estas son las partes pertinentes de mi código:Setup std :: vector in class constructor

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); 
} 

Cuando intento compilar recibo estos mensajes de error:

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 

Sin embargo, cuando cambio la línea en cuestión a:

vector<int> temp(size,0); 
vec = temp; 

Ahora compila sin problemas y obtengo el comportamiento deseado y puedo acceder a mi vector como

vec[i] // i having been defined as an int yada yada yada 

Esta solución está bien, pero me gustaría entender por qué funciona y falla el primer método. Gracias por adelantado.

+2

'nueva vECTOR' devuelve un puntero no es un valor, para que usted sea capaz de asignarle a la variable miembro de' vec' – Chethan

+2

Mi conjetura es que provienen de Java o C# y si es así, mi consejo es grave para obtener primero un buen libro introductorio de C++. –

+0

Y, por favor, siempre publique el código actual mediante el método de copiar y pegar. El código que publicó está incompleto –

Respuesta

18

Just Do:

MyClass::MyClass(int m_size) : size(m_size), vec(m_size, 0) 

Ya pareces saber acerca de las listas de inicializador, por qué no inicializar vectores allí directamente?

vec = new vector<int>(size,0); 

es ilegal porque new devuelve un puntero y, en su caso vec es un objeto.

La segunda opción:

vector<int> temp(size,0); 
vec = temp; 

aunque compila, hace un trabajo extra para ninguna ganancia. Para cuando llegue a la asignación, dos vectores ya se habrán construido y descartado después.

+1

IIRC esto causará advertencias con GCC debido al orden de inicialización; debe ordenar las inicializaciones en la lista de inicializadores de la misma manera que las variables miembro en la clase. – Fiktik

+0

Gracias por el comentario, sobre la base de que he intentado hacer vec = * (nuevo vector (szie, 0)); y eso también funcionó, pero usaré la lista de inicializadores ¡gracias! – fenkerbb

+0

@ user1269950 lo que hizo está mal: crea una pérdida de memoria. 'new' asigna una memoria en el montón, crea un objeto allí y le devuelve un puntero. Lo que hizo fue asignar el contenido de ese objeto a su objeto miembro y luego olvidarse del original, pero aún permanece asignado para siempre. Cuando llame a 'new', siempre debe guardar la dirección que devuelve (en un puntero) y eventualmente invocar' delete' en ese puntero. – Fiktik

8

El uso de vectores es legal en su clase, el problema es la forma en que lo inicialice:

#include <vector> 

class MyClass { 
public: 
    MyClass(int m_size); 

    // ... more things... 
private: 
    int size; 
    vector<int> vec; 
} 

está asignando un puntero a un objeto nuevo vector, como si este objeto vectorial no se ha inicializado.

vec = new vector<int>(size,0); 

Si realmente quiere que esto funcione, debe declarar el objeto vec como:

vector<int> * vec; 

Y no se olvide de añadir un destructor:

MyClass::~MyClass { 
    delete vec; 
} 

Por qué lo hizo funciona cuando se cayó la partícula new? Debido a que está creando un nuevo objeto vector, y sobrescribiendo el de su clase (esto no garantiza que el original se elimine correctamente, sin embargo).

En realidad, no necesita hacer eso. Su objeto vector ya está inicializado (se llama al constructor predeterminado) cuando ha llegado al constructor de MyClass.Si lo que desea es estar seguro de que la memoria se reserva para size artículos:

MyClass::MyClass(int m_size): size(m_size) { 
    vec.reserve(size); 
} 

Si usted quiere que su vector de tener size elementos, entonces:

MyClass::MyClass(int m_size): size(m_size), vec(m_size, 0) 
    {} 

Por último, como uno de los comentaristas señala , el tamaño no es realmente necesario una vez que el vector ha sido construido. Así que usted puede deshacerse de la pieza 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; 
} 

Espero que esto ayude.

+1

@OP - El 'vector' conoce su tamaño, por lo que si todo' size' está haciendo un seguimiento de la cantidad de elementos en 'vector', entonces sugiérele que se deshaga de' size'. –

+0

Muy cierto, modificaré mi respuesta para incluir su comentario. – Baltasarq

1
#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