Mặc dù @Marc đã đưa ra (những gì tôi nghĩ là) một phân tích xuất sắc, một số người có thể thích xem xét mọi thứ từ một góc độ hơi khác.
Một là xem xét một cách hơi khác để thực hiện việc tái phân bổ. Thay vì sao chép tất cả các phần tử từ bộ lưu trữ cũ sang bộ lưu trữ mới ngay lập tức, hãy xem xét chỉ sao chép một phần tử tại một thời điểm - tức là, mỗi khi bạn thực hiện một lần đẩy, nó sẽ thêm phần tử mới vào không gian mới và sao chép chính xác một phần tử hiện có yếu tố từ không gian cũ sang không gian mới. Giả sử hệ số tăng trưởng là 2, khá rõ ràng là khi không gian mới đầy, chúng tôi đã hoàn thành sao chép tất cả các yếu tố từ không gian cũ sang không gian mới và mỗi lần đẩy lại chính xác là thời gian không đổi. Vào thời điểm đó, chúng tôi sẽ loại bỏ không gian cũ, phân bổ một khối bộ nhớ mới có mức tăng gấp đôi và lặp lại quy trình.
Rõ ràng, chúng ta có thể tiếp tục điều này vô thời hạn (hoặc miễn là có sẵn bộ nhớ) và mỗi lần đẩy sẽ liên quan đến việc thêm một yếu tố mới và sao chép một yếu tố cũ.
Một triển khai điển hình vẫn có chính xác cùng số lượng bản sao - nhưng thay vì thực hiện từng bản sao một lần, nó sẽ sao chép tất cả các yếu tố hiện có cùng một lúc. Một mặt, bạn đã đúng: điều đó có nghĩa là nếu bạn nhìn vào các yêu cầu riêng lẻ của Push_back, một số trong số chúng sẽ chậm hơn đáng kể so với những cái khác. Tuy nhiên, nếu chúng ta nhìn vào mức trung bình dài hạn, số lượng sao chép được thực hiện cho mỗi lần gọi Push_back vẫn không đổi, bất kể kích thước của vectơ.
Mặc dù nó không liên quan đến độ phức tạp tính toán, tôi nghĩ rằng đáng để chỉ ra lý do tại sao việc làm như họ lại thuận lợi, thay vì sao chép một yếu tố trên mỗi lần đẩy, do đó thời gian cho mỗi lần đẩy lại không đổi. Có ít nhất ba lý do để xem xét.
Đầu tiên chỉ đơn giản là bộ nhớ có sẵn. Bộ nhớ cũ có thể được giải phóng cho các mục đích sử dụng khác chỉ sau khi sao chép xong. Nếu bạn chỉ sao chép một mục tại một thời điểm, khối bộ nhớ cũ sẽ được phân bổ lâu hơn nhiều. Thực tế, bạn có một khối cũ và một khối mới được phân bổ chủ yếu mọi lúc. Nếu bạn quyết định yếu tố tăng trưởng nhỏ hơn hai (mà bạn thường muốn), bạn sẽ cần nhiều bộ nhớ hơn được phân bổ mọi lúc.
Thứ hai, nếu bạn chỉ sao chép một phần tử cũ tại một thời điểm, việc lập chỉ mục vào mảng sẽ khó khăn hơn một chút - mỗi thao tác lập chỉ mục sẽ cần tìm hiểu xem phần tử tại chỉ mục đã cho hiện đang ở trong khối bộ nhớ cũ hay cái mới Điều đó không quá phức tạp bằng bất kỳ phương tiện nào, nhưng đối với một hoạt động cơ bản như lập chỉ mục vào một mảng, hầu như bất kỳ sự chậm lại nào cũng có thể là đáng kể.
Thứ ba, bằng cách sao chép tất cả cùng một lúc, bạn tận dụng lợi thế của bộ nhớ đệm tốt hơn nhiều. Sao chép tất cả cùng một lúc, bạn có thể hy vọng cả nguồn và đích sẽ nằm trong bộ đệm trong hầu hết các trường hợp, do đó, chi phí của lỗi bộ nhớ cache được khấu hao theo số lượng phần tử sẽ phù hợp với dòng bộ đệm. Nếu bạn sao chép một phần tử tại một thời điểm, bạn có thể dễ dàng bỏ lỡ bộ đệm cho mọi phần tử bạn sao chép. Điều đó chỉ thay đổi hệ số không đổi, không phức tạp, nhưng nó vẫn có thể khá đáng kể - đối với một máy điển hình, bạn có thể dễ dàng mong đợi hệ số từ 10 đến 20.
Có lẽ cũng đáng để xem xét hướng khác trong một lúc: nếu bạn đang thiết kế một hệ thống với các yêu cầu thời gian thực, thì có thể chỉ sao chép một yếu tố tại một thời điểm thay vì cùng một lúc. Mặc dù tốc độ tổng thể có thể (hoặc có thể không) thấp hơn, nhưng bạn vẫn bị giới hạn trên về thời gian thực hiện một lần thực hiện Push_back - giả sử bạn có một công cụ phân bổ thời gian thực (mặc dù vậy, nhiều thời gian thực các hệ thống chỉ đơn giản là cấm phân bổ động bộ nhớ, ít nhất là trong các phần có yêu cầu thời gian thực).