Tại sao sử dụng std :: auto_ptr <> với các thùng chứa tiêu chuẩn là sai?


217

Tại sao nó sai khi sử dụng std::auto_ptr<>với các container tiêu chuẩn?


5
Chắc chắn là +1 về điều này bởi vì tôi đã thấy rất nhiều người mắc phải lỗi này. Đó là một câu hỏi tuyệt vời để hỏi.
twokats

Xin vui lòng đọc các mục liên quan. Câu hỏi này được xem xét ở đây từ phía bên kia. Có thể hữu ích để hiểu thêm về các thùng chứa auto_ptr và STL. stackoverflow.com/questions/8630552/
Mạnh


1
movengữ nghĩa và unique_ptrđược thiết kế để tránh các vấn đề liên quan đến auto_ptr. Trong C ++ 03, ngôn ngữ không đủ mạnh để viết một lớp như thế auto_ptrhoạt động chính xác và an toàn trong mọi tình huống vì trình biên dịch và ngôn ngữ không thể phân biệt giá trị l và r nên một số "hack" đã được sử dụng để có hành vi mong muốn hầu hết thời gian.
Phil1970

Bài viết hay: STL Container và Auto_ptrs - Tại sao họ không trộn quantstart.com/articles/iêu
alfC

Câu trả lời:


124

Tiêu chuẩn C ++ nói rằng một yếu tố STL phải là "sao chép có thể xây dựng" và "có thể gán được." Nói cách khác, một yếu tố phải có thể được chỉ định hoặc sao chép và hai yếu tố độc lập về mặt logic. std::auto_ptrkhông đáp ứng yêu cầu này.

Lấy ví dụ mã này:

class X
{
};

std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);

std::auto_ptr<X> pX = vecX[0];  // vecX[0] is assigned NULL.

Để khắc phục hạn chế này, bạn nên sử dụng std::unique_ptr, std::shared_ptrhoặc std::weak_ptrcon trỏ thông minh hoặc tương đương boost nếu bạn không có C ++ 11. Dưới đây là tài liệu thư viện boost cho các con trỏ thông minh này.


7
Bạn cũng nên xem xét các thùng chứa con trỏ tăng, nếu bạn không cần quyền sở hữu chung.
me22

4
unique_ptrcũng không cho phép sao chép, do đó, một số thao tác STL nhất định sẽ không hoạt động chính xác trừ khi chúng có thể sử dụng ngữ nghĩa di chuyển của nó.
Mike Weller

4
"Để khắc phục hạn chế này, bạn nên sử dụng std::unique_ptr": mẫu lớp đó chỉ có thể tồn tại do ngữ nghĩa di chuyển (đặc tả của nó yêu cầu tham chiếu giá trị), vì vậy về cơ bản nó yêu cầu C ++ 11. Tuy nhiên (và có liên quan) Tiêu chuẩn C ++ 11 không còn nói rằng loại phần tử STL phải là "bản sao có thể xây dựng" và "có thể gán"; là di chuyển-xây dựng và di chuyển đủ điều kiện. Thực tế các unique_ptrtrường hợp chỉ di chuyển có thể xây dựng và di chuyển có thể gán. Nhưng các auto_ptrtrường hợp cũng vậy ! Kết quả là, trong C ++ 11 bạn có thể làm với auto_ptrnhững gì bạn có thể làm với unique_ptr.
Marc van Leeuwen

@MarcvanLeeuwen trừ khi bạn resetreleasekhi cần
ratchet freak

2
@ratchetfreak: Hmm, tôi không hiểu. Gì? "Trừ khi bạn resetrelease", tôi không thấy điều đó áp dụng cho bất cứ điều gì trong bình luận của tôi. Lưu ý rằng cả hai auto_ptrunique_ptrcó cả hai phương thức này, và chúng làm cùng một điều trong cả hai trường hợp.
Marc van Leeuwen

66

Các ngữ nghĩa bản sao của auto_ptrkhông tương thích với các container.

Cụ thể, sao chép cái này auto_ptrsang cái khác không tạo ra hai đối tượng bằng nhau vì một đối tượng đã mất quyền sở hữu con trỏ.

Cụ thể hơn, sao chép một auto_ptrnguyên nhân khiến một trong các bản sao buông con trỏ. Những phần còn lại trong container không được xác định. Do đó, bạn có thể ngẫu nhiên mất quyền truy cập vào con trỏ nếu bạn lưu trữ auto_ptrstrong các thùng chứa.


39

Hai bài viết siêu xuất sắc về chủ đề này:


Bởi vì tôi nghĩ rằng trong gần hai năm qua, anh ta có thể xử lý vấn đề trong tay.
Cún con

27
@DeadMG: vâng, bạn đúng. Nhưng đó không phải là mục đích của tôi. Nếu ai đó đến với chủ đề này đôi khi và muốn tìm hiểu về auto_ptrvà công cụ, những liên kết này sẽ hữu ích, tôi chắc chắn.
Lazer

Có rất nhiều bản sao gần đây hơn.
Cún con

8
@DeadMG: Câu hỏi này không được đóng dưới dạng trùng lặp và do đó mở cho phần mở rộng. Lazer đã nói những gì không được nói trước đây. Tôi đoán anh ấy đến tình cờ.
Sebastian Mach

Các giải thích trong liên kết thứ hai, phân tích vấn đề sau khi gọi sort(), rõ ràng hơn tất cả các câu trả lời ở đây.
hỗn loạn

17

Các thùng chứa STL cần có khả năng sao chép các mục bạn lưu trữ trong chúng và được thiết kế để mong muốn bản gốc và bản sao tương đương nhau. các đối tượng con trỏ tự động có một hợp đồng hoàn toàn khác, theo đó việc sao chép tạo ra sự chuyển giao quyền sở hữu. Điều này có nghĩa là các thùng chứa auto_ptr sẽ thể hiện hành vi lạ, tùy thuộc vào cách sử dụng.

Có một mô tả chi tiết về những gì có thể sai trong mục 8 STL (Scott Meyers) hiệu quả và cũng là một mô tả không chi tiết trong mục C ++ (Scott Meyers) hiệu quả 13.


12

STL container lưu trữ các bản sao của các mặt hàng chứa. Khi auto_ptr được sao chép, nó sẽ đặt ptr cũ thành null. Nhiều phương thức container bị phá vỡ bởi hành vi này.


Nhưng, khi sử dụng unique_ptr bạn có nhận được khá nhiều điều tương tự vì chỉ một unique_ptr có thể có quyền sở hữu đối tượng?
Tracer

2
@Tracer unique_ptrgiống như bất kỳ đối tượng C ++ 11 thích hợp nào chỉ có thể chuyển quyền sở hữu tài nguyên của nó khi được xây dựng di chuyển hoặc được gán, đảm bảo rằng lập trình viên phải cố tình vượt qua một std::move(sourceObject)hoặc tạm thời, thay vì chuyển một giá trị và vô tình / không dự đoán được nó bị biến đổi bởi phân công sao chép ... mà, như đã nhấn mạnh kỹ ở đây, là một vấn đề cốt lõi của auto_ptr.
gạch dưới

4

Tiêu chuẩn C ++ 03 (ISO-IEC 14882-2003) cho biết trong khoản 20.4.5 đoạn 3:

[...] [ Lưu ý: [...] auto_ptr không đáp ứng các yêu cầu CopyConstructible và Assignable cho các thành phần bộ chứa Thư viện Chuẩn và do đó khởi tạo bộ chứa Thư viện Chuẩn với kết quả auto_ptr trong hành vi không xác định. - lưu ý cuối ]

Tiêu chuẩn C ++ 11 (ISO-IEC 14882-2011) nói trong phụ lục D.10.1 đoạn 3:

[...] Lưu ý: [...] Trường hợp auto_ptr đáp ứng các yêu cầu của MoveConstructible và MoveAssignable, nhưng không đáp ứng các yêu cầu của CopyConstructible và CopyAssignable. - lưu ý cuối]

Tiêu chuẩn C ++ 14 (ISO-IEC 14882-2014) cho biết trong phụ lục C.4.2 Phụ lục D: tính năng tương thích:

Thay đổi : Các mẫu lớp auto_ptr, unary_feft và binary_feft, các mẫu hàm Random_shuffle và các mẫu hàm (và các kiểu trả về của chúng) ptr_fun, mem_fun, mem_fun numf, bind1st và bind2nd không được xác định.
Đặt vấn đề : Thay thế bởi các tính năng mới.
Ảnh hưởng đến tính năng gốc : Mã C ++ 2014 hợp lệ sử dụng các mẫu lớp và mẫu hàm này có thể không được biên dịch trong Tiêu chuẩn quốc tế này.

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.