2012-04-06 30 views
7

Tôi biết rằng các biến được phân bổ trên ngăn xếp của hàm đó trở nên không thể tiếp cận khi hàm kết thúc thực thi. Tuy nhiên, các loại vectơ phân bổ các phần tử của chúng trên heap bất kể chúng được phân bổ như thế nào. Ví dụ:Vectơ được phân bổ trên "ngăn xếp" có được chuyển từ hàm này sang hàm khác không?

vector<int> A; 

sẽ phân bổ không gian cho các phần tử trên đống thay vì chồng.

Câu hỏi của tôi là, giả sử tôi có đoạn mã sau:

int main(int argc, char *argv[]) { 
    // initialize a vector 
    vector<int> A = initVector(100000); 

    // do something with the vector... 

    return 0; 
} 


// initialize the vector 
vector<int> initVector(int size) { 
    vector<int> A (size); // initialize the vector "on the stack" 

    // fill the vector with a sequence of numbers... 
    int counter = 0; 
    for (vector<int>::iterator i = A.begin(); i != A.end(); i++) { 
     (*i) = counter++; 
    } 

    return A; 
} 

Tôi có vấn đề truy cập bộ nhớ khi sử dụng vector A trong hàm main? Tôi đã thử điều này nhiều lần và tất cả đều làm việc bình thường, nhưng tôi sợ rằng điều này có thể chỉ là may mắn.

Cách tôi thấy nó là, vector A phân bổ các phần tử của nó trên heap, nhưng nó có một số tham số "trên không" (có thể là kích thước của vectơ) được cấp phát trên chính ngăn xếp đó. Do đó, việc sử dụng vec-tơ trong chức năng chính có thể dẫn đến vấn đề truy cập bộ nhớ nếu các thông số này bị ghi đè bởi một phân bổ khác. Bất kỳ ý tưởng?

+1

Theo logic của bạn, 'int add (int a, int b) {int r = a + b; return r} 'nên có cùng một vấn đề mà bạn nghi ngờ cho' initVector' của bạn ... – delnan

+0

'vector A (size);' => 'A' nằm trên stack nhưng các vị trí bộ nhớ nó trỏ đến nằm trên đống. Các vị trí bộ nhớ tiếp giáp 'size' nằm trên heap, trong khi lớp vectơ giữ con trỏ tới phần tử đầu tiên trên heap. Cho phép xem nếu ai đó sửa chữa tôi. – Mahesh

+0

TBH, tôi đã hơi bối rối bởi loại điều này là tốt. Bất cứ khi nào tôi có bất kỳ nghi ngờ nào, tôi cũng đã phân bổ véc tơ, ví dụ: 'vector * a; a = vectơ mới ; ' và sau đó trả lại con trỏ. –

Trả lời

1

Có, nó sẽ hoạt động bình thường vì bộ nhớ cho các phần tử được phân bổ và đó là những gì sẽ được sử dụng để tạo biến số vector<int> A =. Tuy nhiên, hiệu suất khôn ngoan, nó không phải là ý tưởng tốt nhất.

Tôi sẽ đề nghị thay đổi chức năng của bạn để có những điều sau đây dù

void initVector(vector<int>& a, int size) 

Đối với tài liệu tham khảo thêm về cách sử dụng, vui lòng xem Returning a STL vector from a function…[C++] Returning Vector from Function.

Đối với một tài liệu tham khảo thêm về hoạt động (sử dụng C++ 11), vui lòng xem Proper way (move semantics) to return a std::vector from function calling in C++0x

+0

RVO có lẽ sẽ làm cho thay đổi được đề xuất đó không cần thiết. Nhưng đó là một thực hành tốt anyway. –

+0

Cảm ơn bạn đã liên kết. Tôi đồng ý rằng đây là một phương pháp tốt hơn. Tôi đã luôn luôn có nghi ngờ về cách lớp vector thực sự hoạt động. – alguru

+0

@josephthomas Nếu tôi sử dụng phương pháp của bạn (ví dụ: truyền vector theo tham chiếu), thì tôi có bị buộc phải phân bổ véc tơ bằng 'a = new vector ' không? Hoặc có thể có một cách xung quanh đó? – alguru

4

Khi bạn "return A;" bạn trở lại theo giá trị, vì vậy bạn có được một bản sao của vectơ - C++ tạo ra một cá thể mới và gọi hàm tạo bản sao hoặc toán tử = trên nó. Vì vậy, trong trường hợp này nó không quan trọng nơi bộ nhớ được phân bổ như bạn phải sao chép nó anyway và phá hủy các bản sao cũ (một số tối ưu hóa có thể mặc dù).

Dữ liệu trong vectơ (và tất cả các vùng chứa STL khác) cũng được di chuyển theo giá trị, vì vậy bạn lưu trữ bản sao của các số nguyên chứ không phải con trỏ cho chúng. Điều đó có nghĩa là các đối tượng của bạn có thể được sao chép nhiều lần trong bất kỳ hoạt động vùng chứa nào và chúng phải thực hiện một hàm tạo và/hoặc toán tử gán chính xác. C++ tạo ra chúng cho bạn theo mặc định (chỉ cần gọi ctor sao chép trên tất cả các biến thành viên của bạn), nhưng chúng không phải lúc nào cũng làm điều đúng.

Nếu bạn muốn lưu trữ con trỏ trong vùng chứa STL, hãy cân nhắc sử dụng trình bao bọc con trỏ được chia sẻ (std :: shared_ptr hoặc boost :: shared_ptr). Chúng sẽ đảm bảo bộ nhớ được xử lý chính xác.

0

C++ vector thực sự có hai phần bộ nhớ được liên kết với một con trỏ duy nhất. Cái đầu tiên nằm trong ngăn xếp, và cái thứ hai trong đống. Vì vậy, bạn có các tính năng của cả đống và đống trong một đối tượng duy nhất.

std::vector<int> vec; 
vec.push_back(10); 
vec.push_back(20); 
vec.push_back(30); 
std::cout << sizeof(vec) << std::endl; 

Khi bạn chạy mã đó, bạn sẽ nhận thấy rằng vùng ngăn xếp không chứa các phần tử nhưng vẫn tồn tại. Vì vậy, khi bạn truyền vectơ từ hàm này sang hàm khác, bạn sẽ cần phải thao tác các vùng ngăn xếp, và vectơ sẽ được sao chép giống như bất kỳ đối tượng dựa trên stack nào khác.

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