在类构造函数中设置 std::vector

Posted

技术标签:

【中文标题】在类构造函数中设置 std::vector【英文标题】:Setup std::vector in class constructor 【发布时间】:2012-07-10 01:21:40 【问题描述】:

我正在设计一个将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

这个解决方法没问题,但我想了解它为什么有效并且第一种方法失败了。提前致谢。

【问题讨论】:

new vector 返回一个指针而不是一个值,以便您能够将它分配给您的成员变量vec 我猜你来自 Java 或 C#,如果是这样,我的严肃建议是首先获得一本好的 C++ 入门书籍。 请始终通过复制+粘贴方法发布实际代码。您发布的代码不完整 Aside:你真的需要size 成员吗?回想一下,向量带有自己的大小,始终可以像这样查询:vec.size() 【参考方案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;

虽然它可以编译,但做额外的工作却没有任何收获。当你完成分配时,两个向量已经被构建并被丢弃。

【讨论】:

感谢您的评论,基于它我尝试做 vec = *(new vector(szie,0));这也有效,但我将使用初始化列表谢谢! @user1269950 你做错了——它会造成内存泄漏。 new 在堆上分配内存,在那里创建一个对象并返回一个指向它的指针。您所做的是将该对象的内容分配给您的成员对象,然后忘记原来的对象 - 但它仍然永远保持分配状态。当您调用new 时,您始终必须保存它返回的地址(在指针中)并最终在该指针上调用delete @user1269950 不,不要这样做*(new...)。内存泄漏。【参考方案2】:

在你的类中使用vector是合法的,问题是你如何初始化它:

#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,并且覆盖您的类中的那个(但这并不能保证原始对象被正确消除)。

您实际上不需要这样做。当您到达 MyClass 的构造函数时,您的 vector 对象已经初始化(调用了它的默认构造函数)。如果您只是想确保为 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;

希望这会有所帮助。

【讨论】:

@OP -- vector 知道它的大小,所以如果size 所做的只是跟踪vector 中的元素数量,那么建议你摆脱size .【参考方案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

这将向您展示如何创建一个类 您可以选择使用或不使用初始化类 存在和/或不存在其他参数的向量。

【讨论】:

以上是关于在类构造函数中设置 std::vector的主要内容,如果未能解决你的问题,请参考以下文章

C++ 在类构造函数中填充向量

在类中创建多维 STL 向量

为啥 C++11 会从 std::vector 填充构造函数的原型中移除默认值?

使用 std::vector 时如何将索引信息传递给元素构造函数?

具有可访问构造函数的 std::vector< T >::iterator

MSVC 2015 为 std::vector 选择不正确的构造函数重载