Các vectơ được truyền cho các hàm theo giá trị hoặc bằng tham chiếu trong C ++


94

Tôi đang viết mã bằng C ++. Nếu tôi có một số hàm void foo(vector<int> test)và tôi gọi nó trong chương trình của mình, thì vectơ sẽ được truyền theo giá trị hay tham chiếu? Tôi không chắc vì tôi biết vectơ và mảng tương tự nhau và một hàm như thế void bar(int test[])sẽ vượt qua kiểm tra bằng tham chiếu (con trỏ?) Thay vì theo giá trị. Dự đoán của tôi là tôi sẽ cần phải chuyển vector bằng con trỏ / tham chiếu một cách rõ ràng nếu tôi muốn tránh chuyển theo giá trị nhưng tôi không chắc chắn.


5
C ++ có ngữ nghĩa "truyền theo giá trị", vì vậy nó được truyền theo giá trị. Tuy nhiên, bạn có thể quyết định chuyển qua tham chiếu. Sự lựa chọn thực sự phụ thuộc vào những gì chức năng làm.
juanchopanza

2
sử dụng bằng cách tham chiếu, nếu bạn không muốn hàm thay đổi nội dung vectơ làm cho nó là const, cách khác khôn ngoan chỉ cần chuyển nó bằng tham chiếu. Nó sẽ tránh un-muốn và tốn kém (đôi khi) sao chép
Ali Kazmi

3
Ngoài ra, một tham chiếu không phải là một con trỏ.
Các thuận Croissant

2
@AliKazmi Trừ khi bạn muốn có một bản sao trong phần nội dung của hàm.
juanchopanza

Nó phụ thuộc vào những gì bạn muốn đạt được. Việc sử dụng một trong những con trỏ thông minh tiêu chuẩn đôi khi rất hữu ích, ví dụ: nếu bạn muốn chuyển quyền sở hữu, thì hãy sử dụng unique_ptr. Nhưng thông thường, tôi truyền std :: vector bằng cách tham chiếu.
Erik Alapää

Câu trả lời:


134

Nếu tôi phải đoán, tôi muốn nói rằng bạn đến từ nền tảng Java. Đây là C ++ và mọi thứ được truyền theo giá trị trừ khi bạn chỉ định khác bằng cách sử dụng &-operator (lưu ý rằng toán tử này cũng được sử dụng làm toán tử 'address-of', nhưng trong một ngữ cảnh khác). Tất cả điều này đều được ghi lại đầy đủ, nhưng tôi vẫn sẽ lặp lại:

void foo(vector<int> bar); // by value
void foo(vector<int> &bar); // by reference (non-const, so modifiable inside foo)
void foo(vector<int> const &bar); // by const-reference

Bạn cũng có thể chọn chuyển một con trỏ đến một vector ( void foo(vector<int> *bar)), nhưng trừ khi bạn biết mình đang làm gì và bạn cảm thấy rằng đây thực sự là cách để đi, đừng làm điều này.

Ngoài ra, vectơ không giống như mảng! Bên trong, vector theo dõi một mảng mà nó xử lý việc quản lý bộ nhớ cho bạn, nhưng nhiều vùng chứa STL khác cũng vậy. Bạn không thể truyền một vectơ cho một hàm khi mong đợi một con trỏ hoặc mảng hoặc ngược lại (bạn có thể truy cập vào (con trỏ tới) mảng bên dưới và sử dụng điều này). Vectơ là các lớp cung cấp nhiều chức năng thông qua các hàm thành viên của nó, trong khi con trỏ và mảng là các kiểu tích hợp sẵn. Ngoài ra, các vectơ được cấp phát động (có nghĩa là kích thước có thể được xác định và thay đổi trong thời gian chạy) trong khi các mảng kiểu C được cấp phát tĩnh (kích thước của nó là không đổi và phải được biết tại thời điểm biên dịch), hạn chế việc sử dụng chúng.

Tôi khuyên bạn nên đọc thêm một số điều về C ++ nói chung (cụ thể là phân rã mảng ), và sau đó xem chương trình sau đây minh họa sự khác biệt giữa mảng và con trỏ:

void foo1(int *arr) { cout << sizeof(arr) << '\n'; }
void foo2(int arr[]) { cout << sizeof(arr) << '\n'; }
void foo3(int arr[10]) { cout << sizeof(arr) << '\n'; }
void foo4(int (&arr)[10]) { cout << sizeof(arr) << '\n'; }

int main()
{
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    foo1(arr);
    foo2(arr);
    foo3(arr);
    foo4(arr);
}

2
Ai có thể giúp tôi hiểu về hàm foo4 khai báo cuối cùng được không? Tại sao nó trả về kích thước của mảng thay vì kích thước của con trỏ như trong các hàm khác?
abhishek_M

3
@abhishek_M vì kiểu tham số là tham chiếu. Một tham chiếu chỉ có thể được liên kết với một biểu thức cùng loại. Vì lý do này, mảng không bị phân rã, bởi vì tham chiếu đến một mảng không thể được liên kết với một con trỏ, nó chỉ có thể được liên kết với một mảng cùng kiểu (trong trường hợp này là mảng 10 số nguyên)
bolov

1
c ++ 11 có "ngữ nghĩa di chuyển" và bạn có thể làm điều đó một cách cẩn thận và chuyển theo giá trị (với ngữ nghĩa di chuyển) mà không cần sao chép. Đây là một liên kết đã giúp tôi rất nhiều: mbevin.wordpress.com/2012/11/20/move-semantics
fchen

23

A vectorcó chức năng giống như một mảng. Nhưng, đối với ngôn ngữ vectorlà một kiểu, và intcũng là một kiểu. Đối với một đối số hàm, một mảng thuộc bất kỳ kiểu nào (bao gồm vector[]) được coi là con trỏ. A vector<int>không giống như int[](đối với trình biên dịch). vector<int>không phải là mảng, không tham chiếu và không phải là con trỏ - nó đang được truyền theo giá trị và do đó nó sẽ gọi hàm tạo bản sao.

Vì vậy, bạn phải sử dụng vector<int>&(tốt nhất là với const, nếu hàm không sửa đổi nó) để chuyển nó làm tham chiếu.


Cú pháp để truyền "mảng vectơ" bằng cách tham chiếu đến một hàm là gì?
ab123

void functionName (std :: vector <int> (& vc) [5]) {}
RIanGillis

9

void foo(vector<int> test)

vector sẽ được chuyển theo giá trị trong này.

Bạn có nhiều cách hơn để truyền vectơ tùy thuộc vào ngữ cảnh: -

1) Chuyển qua tham chiếu: - Điều này sẽ cho phép hàm foo thay đổi nội dung của vector. Hiệu quả hơn chuyển theo giá trị vì tránh sao chép vectơ.

2) Truyền qua tham chiếu const: - Điều này hiệu quả cũng như đáng tin cậy khi bạn không muốn hàm thay đổi nội dung của vector.


1

khi chúng ta chuyển vectơ theo giá trị trong một hàm làm đối số, nó chỉ đơn giản tạo ra bản sao của vectơ và không có bất kỳ ảnh hưởng nào xảy ra đối với vectơ được xác định trong hàm main khi chúng ta gọi hàm cụ thể đó. trong khi khi chúng ta truyền vector bằng tham chiếu bất cứ thứ gì được viết trong hàm cụ thể đó, mọi hành động sẽ thực hiện trên vector được xác định trong hàm main hoặc hàm khác khi chúng ta gọi hàm cụ thể đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.