Setup std::vector in class constructor

106,138

Solution 1

Just do:

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

You already seem to know about initializer lists, why not initialize vector there directly?

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

is illegal because new returns a pointer and in your case vec is an object.

Your second option:

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

although it compiles, does extra work for no gain. By the time you reach the assignment, two vectors would already have been constructed and discarded afterwards.

Solution 2

The use of vector is legal in your class, the problem is how you initialize it:

#include <vector>

class MyClass {
public:
    MyClass(int m_size);

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

You are assigning a pointer to a new vector object, as if this vector object was not initialized.

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

If you really want this to work, then you should declare your vec object as:

vector<int> * vec;

And don't forget to add a destructor:

MyClass::~MyClass {
    delete vec;
}

Why did it work when you dropped the new particle? Because you are creating a new object vector, and overwriting the one in your class (this does not guarantee the original one to be correctly eliminated, however).

You actually don't need to do that. Your vector object is already initialized (its default constructor called) when you've reached the constructor of MyClass. If you just want to be sure that memory is reserved for size items:

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

If you want your vector to have size elements, then:

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

Finally, as one of the commenters points out, size is not actually needed once the vector has been constructed. So you can get rid of the size member:

class MyClass {
public:
    MyClass(int m_size): vec(m_size, 0)
        {}

    unsigned int getSize() const
        { return vec.size(); }

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

Hope this helps.

Solution 3

#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 initialize the class with or without the vector with other arguments present and/or not present.

Share:
106,138
fenkerbb
Author by

fenkerbb

Updated on July 09, 2022

Comments

  • fenkerbb
    fenkerbb almost 2 years

    I'm designing a class that has a std::vector<int> as an instance variable. I'm using a std::vector because I need to set its size at runtime. Here are the relevant portions of my 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);
    }
    

    When I attempt to compile I get these error messages:

    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
    

    However, when I change the offending line to:

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

    It now compiles without a hitch and I get the desired behavior and can access my vector as

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

    This workaround is okay, but I would like to understand why it works and the first method fails. Thanks in advance.

  • Fiktik
    Fiktik almost 12 years
    IIRC this will cause warnings with GCC because of the order of initialization - you should order the initializations in initializer list the same way as member variables in the class.
  • fenkerbb
    fenkerbb almost 12 years
    Thanks for the comment, based on it I tried doing vec = *(new vector<int>(szie,0)); and that also worked, but I will use initializer list thank you!
  • Fiktik
    Fiktik almost 12 years
    @user1269950 what you did is wrong - it creates a memory leak. new allocates a memory on the heap, creates an object there and returns a pointer to it. What you did was assign the contents of that object to your member object and then forget about the original one - but it still remains allocated forever. When you call new you always must save the address it returns (in a pointer) and eventually call delete on that pointer!
  • Luchian Grigore
    Luchian Grigore almost 12 years
    @user1269950 no, don't do *(new...). Memory leak.
  • Happy Green Kid Naps
    Happy Green Kid Naps almost 12 years
    @OP -- The vector knows its size, so if all size is doing is keeping track of the number of elements in vector, then suggest you get rid of size.
  • Chandra Shekhar
    Chandra Shekhar over 2 years
    Could you please explain, why we can't put the vec = new vector<int>(size,0); statement in the constructor, it is showing compilation error when I am trying to do so error: no viable overloaded '=' : v= new vector<int>(26, -1). Please help!
  • Baltasarq
    Baltasarq over 2 years
    You cannot do that because vec is not a pointer to a vector object, but a vector object itself. The :vec(m_size, 0) just initializes the vector, you don't need to do anything else. If you really want to create a vector with new, then change the vecmember to be vector<int> *vec. And remember to eliminate it with the delete operator in the destructor!