Подтвердить что ты не робот

Настройка std::vector в конструкторе класса

Я разрабатываю класс с std::vector<int> как переменную экземпляра. Я использую std::vector, потому что мне нужно установить его размер во время выполнения. Вот соответствующие части моего кода:

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

Когда я пытаюсь скомпилировать, я получаю следующие сообщения об ошибках:

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

Однако, когда я меняю строку нарушения на:

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

Теперь он компилируется без заминки, и я получаю желаемое поведение и могу получить доступ к моему вектору как

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

Это обходное решение в порядке, но я хотел бы понять, почему он работает, и первый метод выходит из строя. Спасибо заранее.

4b9b3361

Ответ 1

Просто выполните:

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

Вы уже знаете, что знаете списки инициализаторов, почему бы не инициализировать вектор там напрямую?

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

является незаконным, поскольку new возвращает указатель, а в вашем случае vec - это объект.

Второй вариант:

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

хотя он компилируется, делает дополнительную работу без усиления. К тому времени, как вы достигнете назначения, два вектора уже были бы построены и отброшены впоследствии.

Ответ 2

Использование вектора является законным в вашем классе, проблема заключается в том, как вы его инициализируете:

#include <vector>

class MyClass {
public:
    MyClass(int m_size);

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

Вы назначаете указатель на новый векторный объект, как если бы этот векторный объект не был инициализирован.

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

Если вы действительно хотите, чтобы это сработало, вы должны объявить свой объект vec как:

vector<int> * vec;

И не забудьте добавить деструктор:

MyClass::~MyClass {
    delete vec;
}

Почему это сработало, когда вы уронили частицу new? Поскольку вы создаете новый объект vector и перезаписываете его в своем классе (это, однако, не гарантирует, что исходный будет правильно удален).

Вам не нужно это делать. Ваш объект vector уже инициализирован (его конструктор по умолчанию), когда вы достигли конструктора MyClass. Если вы просто хотите быть уверенным, что память зарезервирована для элементов size:

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

Если вы хотите, чтобы ваш вектор имел элементы size, то:

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

Наконец, как отмечает один из комментаторов, размер фактически не нужен после создания вектора. Таким образом, вы можете избавиться от члена 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;
}

Надеюсь, что это поможет.

Ответ 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 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