2010-08-09 29 views
5
//Using g++ and ubuntu. 
#include <vector> 
using namespace std; 

Định nghĩa một lớp:C++ vector của các lớp học với nhà thầu

class foo(){ 
(...) 
foo(int arg1, double arg2); 
} 

vị thi công:

foo::foo(int arg1, double arg2){ 
(...) //arrays whose length depend upon arg1 and arg2 
} 

Tôi muốn làm điều gì đó như thế này:

vector<foo> bar(10); //error: no matching function for call to 'foo::foo()' 
bar[0] = new foo(123, 4.56); 
(...) 

Một thay thế phương pháp (mà tôi thích ít hơn) là sử dụng push_back:

vector<foo> bar; //works 
bar.push_back(new foo(123, 4.56)); //throws similar error. 
//Omitting the "new" compiles but throws a "double free or corruption (fasttop)" on runtime. 

Tôi muốn các phần tử khác nhau của véc tơ được xây dựng khác nhau, vì vậy tôi không muốn sử dụng "Trình tạo chuỗi lặp lại". Cần làm gì?

Trả lời

4

Tại sao bạn sử dụng new khi không có bộ nhớ động cần phải được tạo? Tất nhiên sử dụng new sẽ không thành công, kết quả là foo* khi push_back chấp nhận foo. (Đó là những gì bạn có vectơ, sau khi tất cả.)

Có gì sai với push_back? Nếu bạn muốn đặt trước bộ nhớ, hãy sử dụng reserve(); việc cung cấp một số trong hàm tạo của vector làm cho nhiều bản sao của thông số thứ hai (được ngụ ý là foo(), không hoạt động do đó lỗi của bạn), không giống như việc đặt trước bộ nhớ.

Nếu làm việc chính xác (không new) treo, lỗi có trong mã của bạn chứ không phải vectơ. Có thể bạn chưa viết một lớp thích hợp để quản lý tài nguyên. * (Ghi The Big Three, sử dụng copy-and-swap idiom.)

* Tôi nói điều này bởi vì bạn nói "//arrays whose length depend upon arg1 and arg2 ", mà tôi nghi ngờ có nghĩa là bạn có new[] trong lớp học của bạn ở đâu đó . Nếu không có Big Three, việc quản lý tài nguyên của bạn sẽ thất bại.

Bạn không nên quản lý tài nguyên, lớp học có một trách nhiệm. Điều đó có nghĩa là nó phải là một mảng động, hoặc sử dụng một mảng động, nhưng không phải cả hai quản lý và sử dụng một mảng động. Vì vậy, yếu tố ra các nguồn lực vào lớp riêng của họ, và sau đó thực hiện một lớp học (của bạn) trong đó sử dụng chúng. Mảng động là std::vector, vì vậy bạn đã thực hiện xong điều đó. Bất kỳ thời gian nào bạn cần một mảng động, hãy sử dụng vector; không bao giờ có lý do để không.

+0

+1 cho một câu trả lời thực sự tốt. Nếu tôi có thể, tôi muốn cung cấp thêm một +1 cho không nói rằng bạn nên luôn luôn sử dụng std :: vector, nhưng bạn nên luôn luôn sử dụng một vector. – Simon

0

std :: vector luôn tạo các phần tử dựa trên hàm tạo mặc định mà bạn chưa xác định trong đoạn mã ở trên.

phương pháp push_back đang đối mặt với vấn đề miễn phí gấp đôi vì bạn không xử lý hàm tạo bản sao.

4
vector<foo> bar(10); //error: no matching function for call to 'foo::foo()' 

này được không vì std::vector constructor bạn đang gọi là

explicit vector (size_type n, const T& value= T(), const Allocator& = Allocator()); 

Như bạn có thể thấy, nó đang cố gắng để lấp đầy vector với 10 cuộc gọi đến constructor mặc định của foo mà không làm hiện hữu.

Ngoài ra, tất cả các ví dụ của bạn có tính năng new sẽ không thành công vì vectơ đang chờ đối tượng thuộc loại foo, không phải foo *. Hơn nữa, thay đổi thành vector<foo *> cũng sẽ không thành công trừ khi bạn thủ công delete mọi thành viên trước khi xóa véc tơ. Nếu bạn thực sự muốn đi tuyến phân bổ bộ nhớ động, hãy tạo vector< shared_ptr<foo> >. shared_ptr có sẵn trong Boost libraries hoặc nếu trình biên dịch của bạn bao gồm thư viện TR1, nó sẽ xuất hiện trong tiêu đề <memory> trong không gian tên std::tr1 hoặc nếu trình biên dịch của bạn có thư viện C++ 0x, nó sẽ sẵn có trong không gian tên std.

gì bạn cũng nên làm như sau:

vector<foo> bar; 
bar.reserve(10); 
bar.push_back(foo(1, 2)); 
... 
... 
bar.push_back(foo(10, 20)); //10 times 
+0

Có lẽ nên đề cập rằng shared_ptr là một phần của thư viện tăng hoặc C++ 0x –

+0

Điều này một mình không hoạt động, nhưng tôi cần phải có lớn 3. –

+0

@Kevin: Tôi nghi ngờ bạn nên sử dụng 'std :: vector' bạn không. Do yếu tố nguồn lực từ việc sử dụng, không làm cả hai. – GManNickG

Các vấn đề liên quan