cách nhanh chóng để sao chép một vectơ vào một vectơ khác


155

Tôi thích hai cách:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}

Bạn làm nó như thế nào?


14
Cái thứ hai có tên sai lệch - vì nó không phải là một bản sao (mặc dù nó nhanh).
Ẩn danh

Câu trả lời:


126

Ví dụ thứ hai của bạn không hoạt động nếu bạn gửi đối số bằng tham chiếu. Ý bạn là

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

Điều đó sẽ làm việc, nhưng một cách dễ dàng hơn là

vector<int> new_(original);

Tốt, nó hoạt động. Nhưng nó không hoạt động cho một loạt các vectơ: ví dụ: vectơ <int> A [n];
ABcDexter

8
Đó là trao đổi, không sao chép.
sdd

1
@sdd - không, không phải vậy. Kiểm tra danh sách đối số. originallà một bản sao của đối số chức năng.
rlbond

249

Họ không giống nhau, phải không? Một cái là bản sao, cái kia là hoán đổi . Do đó tên hàm.

Sở thích của tôi là:

a = b;

Ở đâu ablà vectơ.


3
Trong thực tế, cách tiếp cận được truyền theo giá trị, trình biên dịch gọi hàm tạo sao chép, và sau đó hoán đổi phần tử mới được tạo. Đó là lý do tại sao rlbond đề nghị gọi trực tiếp hàm tạo sao chép để đạt được hiệu quả tương tự.
David Rodríguez - dribeas

1
Tuy nhiên, bạn không thể gọi rlbon mà không có chức năng vượt qua bản gốc là val. Nếu không, bản gốc sẽ là trống rỗng. Giải pháp thứ hai đảm bảo rằng bạn sẽ luôn gọi theo giá trị và do đó bạn sẽ không mất ngày trong vectơ gốc. (Giả sử giao dịch hoán đổi với con trỏ)
Eyad Ebrahim

Không di chuyển các phần tử của b sang a (để lại b với kích thước == 0)?
Jonathan.

1
@Jonathan. Giả sử bạn đang nói về a = bthì không. Chuyển nhượng có nghĩa là: làm cho abằng nhau bmà không thay đổi b. Ngược lại, std::swap(a, b)sẽ trao đổi nội dung của họ (như vậy b's sizemà ngày nay được bất cứ điều gì a' s đã trước đó). Có lẽ bạn đang nghĩ về một hoạt động di chuyển (như xảy ra trong C ++ 11, nhưng không phải trong một nhiệm vụ thông thường như thế này). Một động thái như vậy sẽ để lại btrong trạng thái "ahem" thú vị - xem stackoverflow.com/questions/17730689/ mẹo
Daniel Earwicker

1
@Jonathan. Lưu ý ký hiệu gấp đôi &&. Phiên bản đó sẽ chỉ được sử dụng để tham khảo giá trị. Nó sẽ không khớp với bất kỳ giá trị không phải nào (như btrong ví dụ của tôi ở trên). Bạn có thể biến bthành một bằng cách nói a = std::move(b);Xem en.cppreference.com/w/cpp/lingu/value_carget để biết mức độ phức tạp cao hơn nữa.
Daniel Earwicker

74

Đây là một cách hợp lệ khác để tạo một bản sao của vectơ, chỉ cần sử dụng hàm tạo của nó:

std::vector<int> newvector(oldvector);

Điều này thậm chí còn đơn giản hơn việc sử dụng std::copyđể đi bộ toàn bộ vectơ từ đầu đến cuối cho đến std::back_insertvectơ mới.

Điều đó đang được nói, .swap()một của bạn không phải là một bản sao, thay vào đó nó hoán đổi hai vectơ. Bạn sẽ sửa đổi bản gốc để không chứa bất cứ điều gì nữa! Mà không phải là một bản sao.


19

Trả lời trực tiếp:

  • Sử dụng một =toán tử

Chúng ta có thể sử dụng hàm thành viên công cộng std::vector::operator=của vùng chứa std::vectorđể gán giá trị từ một vectơ cho một vectơ khác.

  • Sử dụng hàm xây dựng

Bên cạnh đó, một hàm xây dựng cũng có ý nghĩa. Hàm xây dựng với một vectơ khác là tham số (ví dụ x) xây dựng một thùng chứa với một bản sao của từng phần tử trong xcùng một thứ tự.

Chú ý:

  • Không được dùng std::vector::swap

std::vector::swapkhông sao chép một vectơ sang một vectơ khác, nó thực sự là các phần tử hoán đổi của hai vectơ, đúng như tên gọi của nó. Nói cách khác, vectơ nguồn để sao chép từ được sửa đổi sau khi std::vector::swapđược gọi, đây có thể không phải là điều bạn mong đợi.

  • Bản sao sâu hay nông?

Nếu các phần tử trong vectơ nguồn là con trỏ tới dữ liệu khác, thì đôi khi cần một bản sao sâu.

Theo wikipedia:

Một bản sao sâu, có nghĩa là các trường bị hủy đăng ký: thay vì tham chiếu đến các đối tượng được sao chép, các đối tượng sao chép mới được tạo cho bất kỳ đối tượng được tham chiếu nào và các tham chiếu đến các đối tượng được đặt trong B.

Trên thực tế, hiện tại không có cách tích hợp sẵn trong C ++ để thực hiện một bản sao sâu. Tất cả các cách được đề cập ở trên là nông. Nếu một bản sao sâu là cần thiết, bạn có thể duyệt qua một vectơ và tạo bản sao của các tài liệu tham khảo theo cách thủ công. Ngoài ra, một iterator có thể được xem xét để duyệt qua. Thảo luận về iterator nằm ngoài câu hỏi này.

Người giới thiệu

Trang std::vectortrên cplusplus.com


14

bạn không nên sử dụng trao đổi để sao chép vectơ, nó sẽ thay đổi vectơ "gốc".

thay vào đó, chuyển bản gốc làm tham số mới.


14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2

-14

Trong trường hợp vectơ ALREADY tồn tại và bạn muốn sao chép, bạn có thể làm điều này:

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());

1
Xin đừng memcpy. Ngoài ra, điều này sẽ không hoạt động vì memcpy có kích thước tính theo byte. Ngoài ra nếu vectơ khác đã tồn tại, bạn có thể thực hiện newVec = oldVectương tự như một trong những câu trả lời khác.
FDinoff

Vâng, bạn đúng. Tôi đã không nhìn thấy điều đó. @FDinoff, mặc dù bên dưới một công trình, tại sao bạn đề nghị không sử dụng memcpy? Nó dường như nhanh hơn nhiều so với newVec = oldVec. memcpy (& newVec.at (0), & oldVec.at (0), oldVec.size () * sizeof (int));
sellod

1
Trong trường hợp chung, Sao chép một đối tượng mà không gọi hàm tạo sao chép của nó có thể dẫn đến các lỗi tinh vi. Trong trường hợp này tôi đã nghĩ rằng họ sẽ có hiệu suất tương tự. Nếu không, tôi sẽ nói rằng vector không được tối ưu hóa hiệu suất, vì nó đã được thực hiện điều này. Bạn đã thực sự viết một điểm chuẩn?
FDinoff

Tôi đã không chỉ trích bạn .. Trưởng nhóm của tôi cũng đề nghị như vậy và tôi đang cố gắng hiểu.
sellod

(Tôi không nghĩ bạn đang chỉ trích tôi.) Vẫn còn điều gì đó bạn không hiểu?
FDinoff
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.