2012-07-10 55 views
12

Tôi đang thiết kế một lớp có một biến thể hiện std::vector<int>. Tôi đang sử dụng std::vector vì tôi cần đặt kích thước của nó khi chạy. Dưới đây là các phần có liên quan của mã của tôi:Thiết lập std :: vector trong hàm tạo lớp

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

Khi tôi cố gắng biên soạn tôi nhận được các thông báo lỗi:

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 

Tuy nhiên, khi tôi thay đổi dòng vi phạm đến:

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

Hiện tại, công cụ biên dịch không có sự cố và tôi nhận được hành vi mong muốn và có thể truy cập vào vectơ của tôi dưới dạng

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

Cách giải quyết này không sao, nhưng tôi muốn hiểu tại sao nó hoạt động và phương pháp đầu tiên không thành công. Cảm ơn trước.

+2

'vector' mới trả về một con trỏ không phải là một giá trị, cho bạn để có thể gán nó vào biến thành viên của bạn 'vec' – Chethan

+2

tôi đoán là bạn đến từ Java hoặc C# và nếu như vậy, lời khuyên của tôi là nghiêm trọng để có được một cuốn C++ giới thiệu tốt, đầu tiên. –

+0

Và vui lòng luôn đăng mã thực tế qua phương thức sao chép + dán. Mã bạn đăng không đầy đủ –

Trả lời

18

Chỉ cần làm:

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

Bạn đã dường như biết về danh sách khởi tạo, tại sao không khởi tạo vector có trực tiếp?

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

là bất hợp pháp vì new trả về con trỏ và trong trường hợp của bạn vec là một đối tượng.

tùy chọn thứ hai của bạn:

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

mặc dù nó biên dịch, làm thêm công việc cho no gain. Khi bạn đạt được nhiệm vụ, hai vectơ đã được xây dựng và loại bỏ sau đó.

+1

IIRC điều này sẽ gây ra cảnh báo với GCC vì thứ tự khởi tạo - bạn nên đặt lệnh khởi tạo trong danh sách khởi tạo giống như cách biến thành viên trong lớp. – Fiktik

+0

Cảm ơn nhận xét, dựa trên nó tôi đã thử làm vec = * (new vector (szie, 0)); và điều đó cũng hiệu quả, nhưng tôi sẽ sử dụng danh sách khởi tạo cảm ơn bạn! – fenkerbb

+0

@ user1269950 những gì bạn đã làm là sai - nó tạo ra một rò rỉ bộ nhớ. 'new' phân bổ một bộ nhớ trên heap, tạo một đối tượng ở đó và trả về một con trỏ tới nó. Những gì bạn đã làm là gán nội dung của đối tượng đó cho đối tượng thành viên của bạn và sau đó quên đi đối tượng gốc - nhưng nó vẫn được phân bổ mãi mãi. Khi bạn gọi 'new' bạn luôn phải lưu địa chỉ mà nó trả về (trong một con trỏ) và cuối cùng gọi' delete' trên con trỏ đó! – Fiktik

8

Việc sử dụng các vector là hợp pháp ở lớp học của bạn, vấn đề là làm thế nào bạn khởi tạo nó:

#include <vector> 

class MyClass { 
public: 
    MyClass(int m_size); 

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

Bạn đang gán một con trỏ đến một đối tượng vector mới, như thể đối tượng vector này không được khởi tạo.

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

Nếu bạn thực sự muốn điều này để làm việc, sau đó bạn nên khai báo các đối tượng vec của bạn như:

vector<int> * vec; 

Và đừng quên thêm một destructor:

MyClass::~MyClass { 
    delete vec; 
} 

Tại sao nó hoạt động khi bạn bỏ hạt new? Vì bạn đang tạo đối tượng mới vector và ghi ghi đè một trong lớp học của bạn (điều này không đảm bảo rằng đối tượng ban đầu được loại bỏ chính xác).

Bạn thực sự không cần thực hiện điều đó. Đối tượng vector của bạn đã được khởi tạo (hàm tạo mặc định của nó được gọi) khi bạn đã đạt đến hàm tạo của MyClass.Nếu bạn chỉ muốn chắc chắn rằng bộ nhớ được dành riêng cho size mục:

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

Nếu bạn muốn vector của bạn để có size yếu tố, sau đó:

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

Cuối cùng, như một trong những bình luận chỉ ra , kích thước là không thực sự cần thiết khi vector đã được xây dựng. Vì vậy, bạn có thể loại bỏ thành viên 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; 
} 

Hy vọng điều này sẽ hữu ích.

+1

@OP - 'vector' biết kích thước của nó, vì vậy nếu tất cả' kích thước' đang làm là theo dõi số lượng phần tử trong 'vector', thì bạn nên loại bỏ' kích thước'. –

+0

Rất đúng, tôi sẽ sửa đổi câu trả lời của tôi để liên quan đến nhận xét của bạn. – 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 
Các vấn đề liên quan