2010-09-13 36 views
64

Tôi nghe thấy auto_ptr không được dùng nữa trong C++ 11. Lý do cho điều này là gì?Tại sao auto_ptr không được dùng nữa?

Ngoài ra, tôi muốn biết sự khác biệt giữa auto_ptrshared_ptr.

+0

có thể trùng lặp của (http://stackoverflow.com/questions/2404115/is-auto-ptr-deprecated) – malat

Trả lời

68

Thay thế trực tiếp cho auto_ptr (hoặc điều gần nhất với mọi người) là unique_ptr. Theo như "vấn đề" đi, nó khá đơn giản: auto_ptr chuyển quyền sở hữu khi nó được gán. unique_ptr cũng chuyển quyền sở hữu, nhưng nhờ vào việc mã hóa các ngữ nghĩa di chuyển và sự kỳ diệu của các tham chiếu rvalue, nó có thể làm như vậy một cách tự nhiên hơn đáng kể. Nó cũng "phù hợp" với phần còn lại của thư viện chuẩn tốt hơn đáng kể (mặc dù, công bằng, một số trong đó là nhờ phần còn lại của thư viện thay đổi để phù hợp với ngữ nghĩa di chuyển thay vì luôn yêu cầu sao chép).

Sự thay đổi tên cũng là (IMO) là một sự chào đón - auto_ptr không thực sự cho bạn biết nhiều về những gì nó cố gắng tự động hóa, trong khi unique_ptr là một mô tả khá hợp lý (nếu terse) về những gì được cung cấp.

+21

Chỉ cần một lưu ý về 'cái tên auto_ptr' [Là auto \ _ptr bị phản đối?]: Tự động cho thấy tự động như trong biến tự động, và nó đề cập đến một điều mà 'auto_ptr' làm: phá hủy tài nguyên được quản lý trong destructor của nó (khi nó đi ra khỏi phạm vi). –

+12

Thông tin khác: Đây là lý do chính thức cho việc không dùng 'auto_ptr': http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html#20.4.5%20-% 20Class% 20template% 20auto_ptr –

+0

@HowardHinnant tài liệu thú vị! nó là lạ trong một cảm giác rằng nếu std :: sort() là có một chuyên môn cho std :: unique_ptr để sử dụng di chuyển ngữ nghĩa khi cần thiết. Tôi tự hỏi tại sao std :: sort() không thể được chuyên cho std :: auto_ptr để sửa vấn đề sao chép được đề cập trong doc. Cảm ơn trước. – Hei

19

shared_ptr có thể được lưu trữ bên trong các vùng chứa. auto_ptr không thể.

BTW unique_ptr thực sự là thay thế trực tiếp auto_ptr, nó kết hợp các tính năng tốt nhất của cả hai std::auto_ptrboost::scoped_ptr.

28

Tôi đã tìm thấy câu trả lời hiện có tuyệt vời, nhưng từ PoV của con trỏ. IMO, một câu trả lời lý tưởng nên có câu trả lời phối cảnh của người dùng/lập trình viên.

Điều đầu tiên đầu tiên (như được chỉ bởi Jerry Coffin trong câu trả lời của ông)

  • auto_ptr có thể được thay thế bằng shared_ptr hoặc unique_ptr tùy thuộc vào tình hình

shared_ptr: Nếu bạn lo lắng về giải phóng của tài nguyên/bộ nhớ VÀ nếu bạn có nhiều hơn một hàm có thể sử dụng đối tượng AT-DIFFERENT lần, sau đó đi với shared_ptr.

Do DIFFERENT-Times, hãy nghĩ về tình huống mà đối tượng-ptr được lưu trữ trong nhiều cấu trúc dữ liệu và sau đó được truy cập. Nhiều chủ đề, tất nhiên là một ví dụ khác.

unique_ptr: Nếu tất cả những gì bạn quan tâm là giải phóng bộ nhớ và quyền truy cập vào đối tượng là SEQUENTIAL, hãy truy cập unique_ptr.

Theo SEQUENTIAL, ý tôi là, tại bất kỳ đối tượng điểm nào sẽ được truy cập từ một ngữ cảnh. Ví dụ. một đối tượng đã được tạo và được sử dụng ngay sau khi tạo bởi người sáng tạo. Sau khi tạo đối tượng được lưu trữ trong FIRST cấu trúc dữ liệu. Sau đó, một trong hai đối tượng bị hủy sau cấu trúc dữ liệu ONE hoặc được chuyển đến cấu trúc dữ liệu SECOND.

Từ dòng này, tôi sẽ giới thiệu _ptr được chia sẻ/duy nhất làm con trỏ thông minh. (auto_ptr cũng là con trỏ thông minh NHƯNG vì những sai sót trong thiết kế của nó, mà chúng không được dùng nữa, và cái mà tôi nghĩ tôi sẽ chỉ ra trong các dòng tiếp theo, chúng không được nhóm lại với con trỏ thông minh.)

Độc lý do quan trọng nhất là tại sao auto_ptr đã phản đối ủng hộ thông minh-con trỏ là phân-ngữ nghĩa Nếu đó không phải là vì lý do đó, họ sẽ có thêm tất cả các goodies mới của ngữ nghĩa di chuyển để auto_ptr thay vì không dùng nó. Vì ngữ nghĩa phân công là tính năng không thích nhất, họ muốn tính năng đó biến mất, nhưng vì có mã được viết sử dụng ngữ nghĩa đó, (mà các ủy ban tiêu chuẩn không thể thay đổi), họ phải bỏ auto_ptr, thay vì sửa đổi nó.

Từ liên kết: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

Loại bài tập hỗ trợ bởi unqiue_ptr phân di chuyển

  • (1)
  • gán con trỏ null (2) phân
  • loại đúc (3)
  • bài tập sao chép (đã xóa!) (4)

Từ: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

Loại bài tập hỗ trợ bởi auto_ptr

  • bản chuyển nhượng (4) thủ phạm

Bây giờ đến lý do tại sao việc giao bản sao chính nó đã không thích, tôi có lý thuyết này:

  1. Không phải tất cả trình đọc sách hoặc tiêu chuẩn
  2. auto_ptr trên mặt của nó, hứa hẹn bạn sở hữu của đối tượng
  3. các little- * (ý định chơi chữ), khoản của auto_ptr, mà không được đọc bởi tất cả các lập trình viên, cho phép, gán một auto_ptr cho một auto_ptr khác, và chuyển quyền sở hữu.
  4. Nghiên cứu cho thấy hành vi này là dành cho 3.1415926535% tất cả việc sử dụng và không được mong đợi trong các trường hợp khác.

Hành vi ngoài ý muốn thực sự không thích và do đó không thích cho auto_ptr.

(Đối với 3.1415926536% người lập trình cố ý chuyển quyền sở hữu C++ 11 đã cho họ std :: move(), điều này làm cho ý định của họ rõ ràng cho tất cả những người thực tập đọc và duy trì mã .)

+1

Vì bạn ** không bao giờ muốn hai giá trị 'auto_ptr' trỏ tới cùng một đối tượng (vì chúng không cho quyền sở hữu chia sẻ, cái đầu tiên chết sẽ để lại với một di sản gây chết người, điều này cũng đúng với' unique_ptr 'sử dụng), bạn có thể đề xuất _what was_ dành cho 96.8584073465% còn lại của tất cả việc sử dụng không? –

+0

Không thể nói cho tất cả chúng, nhưng tôi đoán, họ sẽ * nghĩ * quyền sở hữu đối tượng đang được * di chuyển * và KHÔNG chỉ bị trùng lặp, mà là sai lầm. –

+1

"Nghiên cứu đã hiển thị" :-) – deworde

6

Tuy nhiên, một đảm nhận việc giải thích sự khác biệt ....

về mặt chức năng, C++ 11 của std::unique_ptr là "cố định" std::auto_ptr: cả hai trong số đó là phù hợp khi - tại bất kỳ thời điểm nào trong quá trình thực hiện - nên có một chủ sở hữu con trỏ thông minh duy nhất cho một đối tượng được trỏ tới.

Sự khác biệt quan trọng là trong bản sao-xây dựng hoặc chuyển nhượng từ một con trỏ thông minh un-hết hạn, hiển thị trên => dòng dưới đây:

std::auto_ptr<T> ap(...); 
    std::auto_ptr<T> ap2(get_ap_to_T()); // take expiring ownership 
=> std::auto_ptr<T> ap3(ap); // take un-expiring ownership ala ap3(ap.release()); 
    ap->xyz; // oops... can still try to use ap, expecting it to be non-NULL 

    std::unique_ptr<T> up(...); 
    std::unique_ptr<T> up2(get_up_to_T()); // take expiring ownership 
=> std::unique_ptr<T> up3(up); // COMPILE ERROR: can't take un-expiring ownership 
=> std::unique_ptr<T> up4(std::move(up)); // EXPLICIT code allowed 
=> std::unique_ptr<T> up4(up.release()); // EXPLICIT code allowed 

Ở trên, ap3 lặng lẽ "đánh cắp" quyền sở hữu của *ap, để lại ap bộ đến một số nullptr và vấn đề là có thể xảy ra quá dễ dàng, không có lập trình viên có suy nghĩ thông qua sự an toàn của nó.

Ví dụ, nếu một class/struct có thành viên std::auto_ptr, sau đó thực hiện một bản sao của một thể hiện sẽ release con trỏ từ dụ được sao chép: đó là ngữ nghĩa kỳ lạ và khó hiểu một cách nguy hiểm như thường sao chép cái gì đó không sửa đổi nó. Thật dễ dàng cho lớp/struct tác giả bỏ qua việc giải phóng con trỏ khi lập luận về bất biến và trạng thái, và do đó vô tình cố gắng dereference con trỏ thông minh trong khi null, hoặc vẫn không có quyền truy cập/quyền sở hữu dự kiến ​​của dữ liệu được trỏ tới.

+0

auto_ptr lặng lẽ "đánh cắp" quyền sở hữu +1 – camino

1

auto_ptr không thể được sử dụng trong vùng chứa STL vì nó có một hàm tạo bản sao không đáp ứng các yêu cầu của vùng chứa CopyConstructible. unique_ptr không thực hiện một hàm tạo bản sao, vì vậy các thùng chứa sử dụng các phương thức thay thế. unique_ptr có thể được sử dụng trong các thùng chứa và nhanh hơn cho các thuật toán std hơn shared_ptr.

#include <iostream> 
#include <type_traits> 
#include <vector> 
#include <memory> 

using namespace std; 

int main() { 
    cout << boolalpha; 
    cout << "is_copy_constructible:" << endl; 
    cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl; 
    cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl; 
    cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl; 

    vector<int> i_v; 
    i_v.push_back(1); 
    cout << "i_v=" << i_v[0] << endl; 
    vector<int> i_v2=i_v; 
    cout << "i_v2=" << i_v2[0] << endl; 

    vector< unique_ptr<int> > u_v; 
    u_v.push_back(unique_ptr<int>(new int(2))); 
    cout << "u_v=" << *u_v[0] << endl; 
    //vector< unique_ptr<int> > u_v2=u_v; //will not compile, need is_copy_constructible == true 
    vector< unique_ptr<int> > u_v2 =std::move(u_v); // but can be moved 
    cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl; 

    vector< shared_ptr<int> > s_v; 
    shared_ptr<int> s(new int(3)); 
    s_v.push_back(s); 
    cout << "s_v=" << *s_v[0] << endl; 
    vector< shared_ptr<int> > s_v2=s_v; 
    cout << "s_v2=" << *s_v2[0] << endl; 

    vector< auto_ptr<int> > a_v; //USAGE ERROR 

    return 0; 
} 

>cxx test1.cpp -o test1 
test1.cpp: In function âint main()â: 
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations] 
    vector< auto_ptr<int> > a_v; //USAGE ERROR 
     ^
>./test1 
is_copy_constructible: 
auto_ptr: false 
unique_ptr: false 
shared_ptr: true 
i_v=1 
i_v2=1 
u_v=2 
s_v=3 
s_v2=3 
Các vấn đề liên quan