2012-02-02 43 views
5

đoạn mã sau kết thúc bằng một kết xuất lõi. Tôi làm gì sai?std :: hợp nhất sáp nhập hai std :: vector coredump

std::vector<int> a; 
a.push_back(1); 
a.push_back(4); 
a.push_back(7); 
std::vector<int> b; 
b.push_back(2); 
b.push_back(5); 
b.push_back(8); 
std::vector<int> c; 
c.clear(); 


std::merge(a.begin(), a.end(), b.begin(), b.end(), c.begin()); 
for (it=c.begin(); it!=c.end(); ++it) 
    std::cout << *it << endl; 

Có chức năng hợp nhất nào khác trong stl hoặc tăng cường mà tôi có thể sử dụng không?

Cảm ơn!

Trả lời

2
std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c)); 
                ^^^^^^^^^^^^^^^^^^^^^^^ 

Cái này là nếu bạn vượt qua c.begin(), chức năng hợp nhất sẽ bắt đầu các giá trị văn vào *c.begin(), *(c.begin() + 1) vv, dẫn đến hành vi không xác định, trong đó có bãi chứa lõi. Bạn có hai lựa chọn ở đây.

  • Đảm bảo c đủ lớn để giữ tất cả các giá trị hợp nhất sẽ ghi vào đó. Ví dụ: bạn có thể gọi số c.resize(a.size()+b.size()); trước khi gọi merge
  • Chuyển số std::back_insert_iterator. Ví dụ về nó được đưa ra ngay từ đầu trong câu trả lời của tôi. Mỗi lần bạn làm *it = x trong đó itback_insert_iterator, nó sẽ push_back x vào vùng chứa bên dưới.

Thông tin về trình lặp chèn lặp có thể được tìm thấy here. back_inserter chỉ là một chức năng tiện lợi để bạn không viết nhiều đối số mẫu.

9

Vấn đề là c của bạn trống vì đã được khởi tạo mà không có phần tử nào, chưa kể đến cuộc gọi không cần thiết đến clear(). std::merge() mất một đối số đầu ra đầu ra làm đối số cuối cùng của nó. Nếu c.begin() đề cập đến sự bắt đầu của số std::vector rằng đã chứa đủ yếu tố, thì đây không phải là vấn đề — những yếu tố đó sẽ chỉ bị ghi đè. Vì vậy, bạn đang gọi hành vi không xác định bằng cách viết các giá trị vào bộ nhớ qua phần cuối của vectơ.

Để đảm bảo rằng c có đủ không gian cho các yếu tố, bạn có thể làm điều này:

c.resize(a.size() + b.size()); 
std::merge(a.begin(), a.end(), b.begin(), b.end(), c.begin()); 

Tuy nhiên, nó là thành ngữ hơn để sử dụng một std::back_insert_iterator, một iterator đầu ra mà các cuộc gọi push_back(). Để có hiệu quả tốt hơn, bạn có thể gọi reserve() trên véc tơ trước. Điều này đảm bảo rằng c chỉ cần phân bổ bộ nhớ một lần, thay vì khi nó phát triển trong khi gọi đến std::merge(). Giải pháp cuối cùng trông như thế này:

#include <iterator> 

// ... 

c.reserve(a.size() + b.size()); 
std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c)); 
+0

Câu trả lời của bạn là đúng, nhưng tôi sẽ không sử dụng cụm từ 'dự trữ', vì nó có nghĩa là một điều hoàn toàn khác với 'thay đổi kích thước'. –

+0

Tại sao bạn chọn gọi giải pháp thứ hai “tốt hơn”? Tôi muốn nói ngược lại vì kích thước được biết và biến thể đầu tiên chắc chắn hiệu quả hơn và không thực sự phức tạp hơn thứ hai. –

+1

@KonradRudolph: cái thứ hai ít bị lỗi hơn, và nói chung hơn, bạn có thể biết kích thước trong trường hợp này, nhưng đôi khi bạn thì không. – Fanael

2

Bạn đang cố gắng để lưu trữ các kết quả trong c, đó là trống rỗng, và như vậy, nó không có đủ không gian để lưu trữ tất cả (trên thực tế, nó doesn không có đủ không gian để lưu trữ mọi thứ). Cố gắng sử dụng back_insert_iterator, mà sẽ push_back các yếu tố thay vì:

std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c)); 
1

c là không đủ lớn để giữ hợp nhất.Hãy thử:

#include <iterator> 
... 
std::merge(a.begin(), a.end(), 
      b.begin(), b.end(), 
      std::back_inserter(c)); 
Các vấn đề liên quan