Một con trỏ thông minh là gì và khi nào tôi nên sử dụng một con trỏ?


1820

Một con trỏ thông minh là gì và khi nào tôi nên sử dụng một con trỏ?



2
Lưu ý rằng việc triển khai std :: auto_ptr trong Visual Studio 2005 bị phá vỡ khủng khiếp. <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842 Sử dụng thay vào đó hãy tăng cường
Richard

25
Hai bài viết xuất sắc về chủ đề: - Con trỏ thông minh - Cái gì, tại sao, cái nào? - Chuyên gia của tuần # 25
Lazer

1
Đây là chương (miễn phí) của Alexandrescu về sự khéo léo của việc tạo ra các con trỏ thông minh có các hương vị khác nhau: notifyit.com/articles/article.aspx?p=31529 Trong quá trình thực hiện, anh ta sử dụng các đối số mẫu làm "chính sách" để chỉ định thuộc tính nào mình muốn ( ví dụ: đếm tham chiếu), trong khi thư viện chuẩn sử dụng các lớp riêng biệt. Lưu ý rằng anh ta cũng đã viết trước khi các tài liệu tham khảo rvalue có sẵn để làm cho một cái gì đó như std :: unique_ptr có thể.
kim loại

Tôi muốn thêm một điểm nữa cho câu hỏi trên, con trỏ thông minh std :: shared_ptr không có toán tử đăng ký và không hỗ trợ số học của nhà thơ, chúng ta có thể sử dụng get () để lấy con trỏ tích hợp.
suresh m

Câu trả lời:


1884

CẬP NHẬT

Câu trả lời này khá cũ và mô tả những gì "tốt" vào thời điểm đó, đó là những gợi ý thông minh được cung cấp bởi thư viện Boost. Kể từ C ++ 11, các thư viện chuẩn đã được cung cấp đủ con trỏ thông minh loại, và vì vậy bạn nên ủng hộ việc sử dụng std::unique_ptr, std::shared_ptrstd::weak_ptr.

Cũng có std::auto_ptr. Nó rất giống với một con trỏ có phạm vi, ngoại trừ việc nó cũng có khả năng nguy hiểm "đặc biệt" được sao chép - điều này cũng bất ngờ chuyển quyền sở hữu.
Nó không được dùng trong C ++ 11 và bị xóa trong C ++ 17 , vì vậy bạn không nên sử dụng nó.

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

TRẢ LỜI

Một con trỏ thông minh là một lớp bao bọc một con trỏ C ++ 'thô' (hoặc 'trần'), để quản lý thời gian tồn tại của đối tượng được trỏ tới. Không có loại con trỏ thông minh duy nhất, nhưng tất cả chúng đều cố gắng trừu tượng một con trỏ thô theo cách thực tế.

Con trỏ thông minh nên được ưu tiên hơn con trỏ thô. Nếu bạn cảm thấy cần sử dụng con trỏ (trước tiên hãy xem xét nếu bạn thực sự làm như vậy), thông thường bạn sẽ muốn sử dụng một con trỏ thông minh vì điều này có thể làm giảm bớt nhiều vấn đề với con trỏ thô, chủ yếu là quên xóa đối tượng và rò rỉ bộ nhớ.

Với con trỏ thô, lập trình viên phải tiêu diệt rõ ràng đối tượng khi nó không còn hữu ích.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Một con trỏ thông minh bằng cách so sánh xác định một chính sách khi đối tượng bị phá hủy. Bạn vẫn phải tạo đối tượng, nhưng bạn không còn phải lo lắng về việc phá hủy nó.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

Chính sách đơn giản nhất được sử dụng liên quan đến phạm vi của đối tượng trình bao bọc con trỏ thông minh, chẳng hạn như được thực hiện bởi boost::scoped_ptrhoặc std::unique_ptr.

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Lưu ý rằng các std::unique_ptrtrường hợp không thể được sao chép. Điều này ngăn con trỏ bị xóa nhiều lần (không chính xác). Tuy nhiên, bạn có thể chuyển các tham chiếu đến nó xung quanh cho các chức năng khác mà bạn gọi.

std::unique_ptrs rất hữu ích khi bạn muốn gắn thời gian tồn tại của đối tượng với một khối mã cụ thể hoặc nếu bạn nhúng nó dưới dạng dữ liệu thành viên bên trong một đối tượng khác, thời gian tồn tại của đối tượng đó. Đối tượng tồn tại cho đến khi khối mã chứa được thoát ra hoặc cho đến khi chính đối tượng chứa bị phá hủy.

Một chính sách con trỏ thông minh phức tạp hơn liên quan đến việc tham chiếu đếm con trỏ. Điều này không cho phép con trỏ được sao chép. Khi "tham chiếu" cuối cùng đến đối tượng bị hủy, đối tượng sẽ bị xóa. Chính sách này được thực hiện bởi boost::shared_ptrstd::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Con trỏ đếm tham chiếu rất hữu ích khi thời gian tồn tại của đối tượng của bạn phức tạp hơn nhiều và không được gắn trực tiếp vào một phần mã cụ thể hoặc đối tượng khác.

Có một nhược điểm đối với con trỏ đếm tham chiếu - khả năng tạo tham chiếu lơ lửng:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Một khả năng khác là tạo tham chiếu vòng tròn:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Để khắc phục sự cố này, cả Boost và C ++ 11 đều đã xác định a weak_ptrđể xác định tham chiếu yếu (không đếm được) đến a shared_ptr.


7
Bạn có nghĩa là std::auto_ptr<MyObject> p1 (new MyObject());thay vì std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq

35
Câu trả lời tuyệt vời. Sẽ thật tuyệt nếu nó được cập nhật cho c ++ 11. Tôi tìm thấy câu trả lời này để tìm kiếm thông tin về tiêu chuẩn 11 mới và thật tuyệt nếu khách truy cập trong tương lai có thể tìm thấy thông tin cập nhật. Tôi biết auto_ptr đã không được chấp nhận. Tôi tin rằng shated_ptr và yếu_ptr tồn tại như được mô tả và tôi nghĩ rằng scoped_ptr hiện là unique_ptr trong tiêu chuẩn. Nếu điều này là đúng, câu trả lời này có thể được cập nhật không?
SaulBack

16
Để nói rằng khả năng tạo ra một tham chiếu lơ lửng là một nhược điểm đối với các con trỏ được tính tham chiếu là hoàn toàn điên rồ. Các tham chiếu lơ lửng có thể là một nhược điểm của bất kỳ con trỏ C ++ nào . Trong thực tế, chính xác đó là nhược điểm mà con trỏ thông minh có ý định làm giảm bớt .
Michael Dorst

16
Nếu bạn khai báo một con trỏ tới một con trỏ thông minh (như đã được thực hiện trong ví dụ), bạn sẽ từ bỏ tất cả các lợi ích của con trỏ thông minh. Đây không phải là một nhược điểm hay lỗi thiết kế, nó là cách sử dụng ngu ngốc nhất có thể tưởng tượng.
Michael Dorst

3
A const std::auto_ptran toàn để sử dụng, nếu bạn bị mắc kẹt với C ++ 03. Tôi đã sử dụng nó cho mẫu pimpl khá nhiều cho đến khi tôi có quyền truy cập vào C ++ 11.
Toby Speight

303

Đây là một câu trả lời đơn giản cho những ngày này của C ++ hiện đại (C ++ 11 trở lên):

  • Một con trỏ thông minh là gì?
    Đây là loại có giá trị có thể được sử dụng như con trỏ, nhưng cung cấp tính năng bổ sung của quản lý bộ nhớ tự động: Khi một con trỏ thông minh không còn được sử dụng, bộ nhớ mà nó trỏ tới sẽ bị hủy (xem thêm định nghĩa chi tiết hơn trên Wikipedia ).
  • Khi nào tôi nên sử dụng một?
    Trong mã liên quan đến việc theo dõi quyền sở hữu của một phần bộ nhớ, phân bổ hoặc phân bổ lại; con trỏ thông minh thường giúp bạn tiết kiệm nhu cầu thực hiện những điều này một cách rõ ràng.
  • Nhưng con trỏ thông minh nào tôi nên sử dụng trong trường hợp nào?
    • Sử dụng std::unique_ptrkhi bạn không có ý định giữ nhiều tài liệu tham khảo cho cùng một đối tượng. Ví dụ: sử dụng nó cho một con trỏ tới bộ nhớ được cấp phát khi nhập một số phạm vi và được phân bổ lại khi thoát khỏi phạm vi.
    • Sử dụng std::shared_ptrkhi bạn muốn tham chiếu đến đối tượng của mình từ nhiều nơi - và không muốn đối tượng của mình bị phân bổ cho đến khi tất cả các tham chiếu này tự biến mất.
    • Sử dụng std::weak_ptrkhi bạn muốn tham chiếu đến đối tượng của mình từ nhiều nơi - đối với những tham chiếu mà bạn có thể bỏ qua và phân bổ (vì vậy họ sẽ chỉ lưu ý đối tượng đã biến mất khi bạn cố gắng hủy đăng ký).
    • Không sử dụng các boost::con trỏ thông minh hoặc std::auto_ptrngoại trừ trong các trường hợp đặc biệt mà bạn có thể đọc lên nếu bạn phải.
  • Này, tôi không hỏi nên dùng cái nào!
    Ah, nhưng bạn thực sự muốn, thừa nhận nó.
  • Vậy khi nào tôi nên sử dụng con trỏ thường xuyên?
    Chủ yếu là trong mã mà không biết đến quyền sở hữu bộ nhớ. Điều này thường có trong các hàm lấy một con trỏ từ một nơi khác và không phân bổ cũng không phân bổ và không lưu trữ một bản sao của con trỏ vượt quá sự thực thi của chúng.

5
Điều đáng chú ý là trong khi các con trỏ thông minh (sở hữu) giúp quản lý bộ nhớ phù hợp, thì các con trỏ thô (không sở hữu) vẫn hữu ích cho các mục đích tổ chức khác trong cấu trúc dữ liệu. Herb Sutter đã trình bày tuyệt vời về vấn đề này tại CppCon 2016, mà bạn có thể thấy trên YouTube: Leak-Freedom trong C ++ ... Theo mặc định.
wiktor.wandachowicz

1
@ wiktor.wandachowicz T*std::unique_ptr<T>những gì std::weak_ptr<T>std::shared_ptr<T>
Caleth

@Caleth: Không, tôi sẽ không nói như vậy.
einpoklum

1
@TonyTannous: Với sự tôn trọng - Đó là một chỉnh sửa lớn; và tôi không cảm thấy câu trả lời của mình, đó là trừu tượng, cần nó. Tôi đề nghị bạn làm cho ví dụ một câu trả lời riêng biệt, trên liên kết đến nó trong một bình luận.
einpoklum

112

Con trỏ thông minh là một loại giống như con trỏ với một số chức năng bổ sung, ví dụ như giải quyết bộ nhớ tự động, đếm tham chiếu, v.v.

Giới thiệu nhỏ có sẵn trên trang Con trỏ thông minh - Cái gì, tại sao, cái nào? .

Một trong những loại con trỏ thông minh đơn giản là std::auto_ptr(chương 20.4.5 của tiêu chuẩn C ++), cho phép tự động phân bổ bộ nhớ khi nó nằm ngoài phạm vi và mạnh hơn so với sử dụng con trỏ đơn giản khi ném ngoại lệ, mặc dù kém linh hoạt hơn.

Một loại tiện lợi khác là boost::shared_ptrthực hiện đếm tham chiếu và tự động giải phóng bộ nhớ khi không còn tham chiếu đến đối tượng. Điều này giúp tránh rò rỉ bộ nhớ và dễ sử dụng để thực hiện RAII .

Chủ đề được trình bày chuyên sâu trong cuốn sách "Các mẫu C ++: Hướng dẫn hoàn chỉnh" của David Vandevoorde, Nicolai M. Josuttis , chương 20. Con trỏ thông minh. Một số chủ đề được bảo hiểm:

  • Bảo vệ chống ngoại lệ
  • Chủ sở hữu, (lưu ý, std :: auto_ptr là triển khai loại con trỏ thông minh như vậy)
  • Thu nhận tài nguyên là khởi tạo (Điều này thường được sử dụng để quản lý tài nguyên ngoại lệ trong C ++)
  • Hạn chế người giữ
  • Đếm tham chiếu
  • Truy cập truy cập đồng thời
  • Phá hủy và giao dịch

2
Cảnh báo std::auto_ptrkhông được chấp nhận và không được khuyến khích vì bạn có thể vô tình chuyển quyền sở hữu. - C ++ 11 loại bỏ sự cần thiết của Boost, sử dụng: std::unique_ptr, std::shared_ptrstd::weak_ptr
ninMonkey

42

Các định nghĩa được cung cấp bởi Chris, Sergdev và Llyod là chính xác. Tôi thích một định nghĩa đơn giản hơn, chỉ để giữ cho cuộc sống của tôi đơn giản: Một con trỏ thông minh chỉ đơn giản là một lớp làm quá tải các toán tử ->*toán tử. Điều đó có nghĩa là đối tượng của bạn trông giống như một con trỏ nhưng bạn có thể làm cho nó hoạt động tốt hơn, bao gồm đếm tham chiếu, phá hủy tự động, v.v. shared_ptrauto_ptrlà đủ trong hầu hết các trường hợp, nhưng đi kèm với tập hợp các đặc điểm nhỏ của riêng chúng.


30

Một con trỏ thông minh giống như một con trỏ (gõ) thông thường, như "char *", ngoại trừ khi chính con trỏ đi ra khỏi phạm vi thì những gì nó trỏ đến cũng bị xóa. Bạn có thể sử dụng nó giống như một con trỏ thông thường, bằng cách sử dụng "->", nhưng không phải nếu bạn cần một con trỏ thực sự cho dữ liệu. Vì thế, bạn có thể sử dụng "& * ptr".

Nó rất hữu ích cho:

  • Các đối tượng phải được phân bổ mới, nhưng bạn muốn có cùng thời gian tồn tại với thứ gì đó trên ngăn xếp đó. Nếu đối tượng được gán cho một con trỏ thông minh, thì chúng sẽ bị xóa khi chương trình thoát khỏi chức năng / khối đó.

  • Thành viên dữ liệu của các lớp, do đó, khi đối tượng bị xóa, tất cả dữ liệu thuộc sở hữu cũng bị xóa, không có bất kỳ mã đặc biệt nào trong hàm hủy (bạn sẽ cần chắc chắn rằng hàm hủy là ảo, điều này hầu như luôn luôn là một việc nên làm) .

Bạn có thể không muốn sử dụng một con trỏ thông minh khi:

  • ... Con trỏ không thực sự sở hữu dữ liệu ... tức là khi bạn chỉ sử dụng dữ liệu, nhưng bạn muốn nó tồn tại chức năng mà bạn đang tham chiếu nó.
  • ... Con trỏ thông minh sẽ không bị phá hủy vào một lúc nào đó. Bạn không muốn nó ngồi trong bộ nhớ không bao giờ bị phá hủy (chẳng hạn như trong một đối tượng được phân bổ động nhưng sẽ không bị xóa rõ ràng).
  • ... Hai con trỏ thông minh có thể trỏ đến cùng một dữ liệu. (Tuy nhiên, có những con trỏ thông minh hơn sẽ xử lý ... điều đó được gọi là đếm tham chiếu .)

Xem thêm:


18

Hầu hết các loại con trỏ thông minh xử lý việc xử lý đối tượng con trỏ tới bạn. Nó rất tiện dụng vì bạn không phải suy nghĩ về việc vứt bỏ đồ vật bằng tay nữa.

Các con trỏ thông minh được sử dụng phổ biến nhất là std::tr1::shared_ptr(hoặc boost::shared_ptr), và, ít phổ biến hơn , std::auto_ptr. Tôi khuyên bạn nên sử dụng thường xuyên shared_ptr.

shared_ptrrất linh hoạt và xử lý nhiều tình huống xử lý khác nhau, bao gồm cả các trường hợp các đối tượng cần được "vượt qua ranh giới DLL" (trường hợp ác mộng phổ biến nếu các libcs khác nhau được sử dụng giữa mã của bạn và DLL).


18

Một con trỏ thông minh là một đối tượng hoạt động giống như một con trỏ, nhưng cũng cung cấp kiểm soát về xây dựng, phá hủy, sao chép, di chuyển và hội nghị.

Người ta có thể thực hiện con trỏ thông minh của riêng mình, nhưng nhiều thư viện cũng cung cấp triển khai con trỏ thông minh, mỗi cái có những ưu điểm và nhược điểm khác nhau.

Ví dụ: Boost cung cấp các triển khai con trỏ thông minh sau:

  • shared_ptr<T>là một con trỏ để Tsử dụng số tham chiếu để xác định khi nào đối tượng không còn cần thiết.
  • scoped_ptr<T>là một con trỏ tự động bị xóa khi nó đi ra khỏi phạm vi. Không có nhiệm vụ là có thể.
  • intrusive_ptr<T>là một con trỏ đếm tham chiếu khác. Nó cung cấp hiệu suất tốt hơn shared_ptr, nhưng yêu cầu loại Tđể cung cấp cơ chế đếm tham chiếu của riêng nó.
  • weak_ptr<T>là một con trỏ yếu, làm việc kết hợp với shared_ptrđể tránh các tham chiếu tròn.
  • shared_array<T>là như thế shared_ptr, nhưng đối với mảng của T.
  • scoped_array<T>là như thế scoped_ptr, nhưng đối với mảng của T.

Đây chỉ là một mô tả tuyến tính của từng loại và có thể được sử dụng theo nhu cầu, để biết thêm chi tiết và ví dụ người ta có thể xem tài liệu về Boost.

Ngoài ra, thư viện chuẩn C ++ cung cấp ba con trỏ thông minh; std::unique_ptrcho quyền sở hữu duy nhất, std::shared_ptrcho sở hữu chung và std::weak_ptr. std::auto_ptrtồn tại trong C ++ 03 nhưng hiện không dùng nữa.


Vui lòng giải thích lý do tại sao scoped_ptrkhông giống như khai báo cục bộ const unique_ptr- cũng bị xóa khi thoát khỏi phạm vi.
einpoklum

11

Đây là Liên kết cho các câu trả lời tương tự: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Một con trỏ thông minh là một đối tượng hoạt động, trông và cảm thấy giống như một con trỏ bình thường nhưng cung cấp nhiều chức năng hơn. Trong C ++, các con trỏ thông minh được triển khai như các lớp mẫu đóng gói một con trỏ và ghi đè các toán tử con trỏ chuẩn. Họ có một số lợi thế so với con trỏ thông thường. Chúng được đảm bảo được khởi tạo là con trỏ null hoặc con trỏ tới một đối tượng heap. Cảm ứng thông qua một con trỏ null được kiểm tra. Không cần xóa là cần thiết. Các đối tượng được tự động giải phóng khi con trỏ cuối cùng với chúng đã biến mất. Một vấn đề quan trọng với những con trỏ thông minh này là không giống như các con trỏ thông thường, chúng không tôn trọng sự kế thừa. Con trỏ thông minh là không hấp dẫn cho mã đa hình. Đưa ra dưới đây là một ví dụ cho việc thực hiện các con trỏ thông minh.

Thí dụ:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Lớp này triển khai một con trỏ thông minh đến một đối tượng thuộc loại X. Bản thân đối tượng nằm trên heap. Đây là cách sử dụng nó:

smart_pointer <employee> p= employee("Harris",1333);

Giống như các toán tử quá tải khác, p sẽ hoạt động như một con trỏ thông thường,

cout<<*p;
p->raise_salary(0.5);

9

http://en.wikipedia.org/wiki/Smart_pulum

Trong khoa học máy tính, một con trỏ thông minh là một kiểu dữ liệu trừu tượng mô phỏng một con trỏ trong khi cung cấp các tính năng bổ sung, chẳng hạn như thu thập rác tự động hoặc kiểm tra giới hạn. Các tính năng bổ sung này nhằm giảm các lỗi gây ra bởi việc sử dụng sai con trỏ trong khi vẫn giữ được hiệu quả. Con trỏ thông minh thường theo dõi các đối tượng trỏ đến chúng nhằm mục đích quản lý bộ nhớ. Việc sử dụng sai các con trỏ là một nguồn chính của các lỗi: việc phân bổ, phân bổ và tham chiếu liên tục phải được thực hiện bởi một chương trình được viết bằng con trỏ làm cho rất có thể xảy ra rò rỉ bộ nhớ. Con trỏ thông minh cố gắng ngăn chặn rò rỉ bộ nhớ bằng cách tự động phân bổ tài nguyên: khi con trỏ tới một đối tượng (hoặc cuối cùng trong một loạt các con trỏ) bị phá hủy,


6

Đặt T là một lớp trong hướng dẫn này Con trỏ trong C ++ có thể được chia thành 3 loại:

1) Con trỏ thô :

T a;  
T * _ptr = &a; 

Họ giữ một địa chỉ bộ nhớ đến một vị trí trong bộ nhớ. Sử dụng thận trọng, vì các chương trình trở nên phức tạp khó theo dõi.

Con trỏ có dữ liệu const hoặc địa chỉ {Đọc ngược}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Con trỏ tới kiểu dữ liệu T là const. Có nghĩa là bạn không thể thay đổi kiểu dữ liệu bằng con trỏ. tức là *ptr1 = 19; sẽ không làm việc. Nhưng bạn có thể di chuyển con trỏ. tức là ptr1++ , ptr1--; vv sẽ làm việc. Đọc ngược: con trỏ để gõ T là const

  T * const ptr2 ;

Một con trỏ const đến kiểu dữ liệu T. Có nghĩa là bạn không thể di chuyển con trỏ nhưng bạn có thể thay đổi giá trị được trỏ bởi con trỏ. tức là *ptr2 = 19sẽ làm việc nhưng ptr2++ ; ptr2--vv sẽ không hoạt động. Đọc ngược: const con trỏ đến một loại T

const T * const ptr3 ; 

Một con trỏ const tới kiểu dữ liệu const T. Có nghĩa là bạn không thể di chuyển con trỏ cũng như không thể thay đổi con trỏ kiểu dữ liệu thành con trỏ. I E . ptr3-- ; ptr3++ ; *ptr3 = 19;sẽ không làm việc

3) Con trỏ thông minh : { #include <memory>}

Con trỏ dùng chung :

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

Được thực hiện bằng cách sử dụng tính tham chiếu để theo dõi có bao nhiêu "vật" trỏ đến đối tượng được trỏ bởi con trỏ. Khi số này về 0, đối tượng sẽ tự động bị xóa, tức là đối tượng bị xóa khi tất cả các share_ptr trỏ đến đối tượng nằm ngoài phạm vi. Điều này thoát khỏi sự đau đầu của việc phải xóa các đối tượng mà bạn đã phân bổ bằng cách sử dụng mới.

Con trỏ yếu: Giúp xử lý tham chiếu theo chu kỳ phát sinh khi sử dụng Con trỏ chung Nếu bạn có hai đối tượng được trỏ bởi hai con trỏ chia sẻ và có một con trỏ chia sẻ nội bộ trỏ đến từng con trỏ được chia sẻ khác thì sẽ có một tham chiếu theo chu kỳ và đối tượng sẽ không bị xóa khi con trỏ chia sẻ đi ra khỏi phạm vi. Để giải quyết vấn đề này, hãy thay đổi thành viên nội bộ từ shared_ptr thành yếu_ptr. Lưu ý: Để truy cập phần tử được trỏ bởi một con trỏ yếu, hãy sử dụng lock (), điều này trả về một yếu_ptr.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

Xem: Khi nào std :: yếu_ptr hữu ích?

Con trỏ độc đáo: Con trỏ thông minh có trọng lượng nhẹ với quyền sở hữu độc quyền. Sử dụng khi con trỏ trỏ đến các đối tượng duy nhất mà không chia sẻ các đối tượng giữa các con trỏ.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Để thay đổi đối tượng được trỏ đến bởi ptr duy nhất, hãy sử dụng di chuyển ngữ nghĩa

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Tài liệu tham khảo: Về cơ bản chúng có thể là mặc dù là con trỏ const, tức là một con trỏ là const và không thể di chuyển với cú pháp tốt hơn.

Xem: Sự khác biệt giữa biến con trỏ và biến tham chiếu trong C ++ là gì?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Tham khảo: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Cảm ơn Andre vì đã chỉ ra câu hỏi này.


3

Một con trỏ thông minh là một lớp, một bao bọc của một con trỏ bình thường. Không giống như con trỏ thông thường, vòng đời của điểm thông minh dựa trên số tham chiếu (thời gian đối tượng con trỏ thông minh được chỉ định). Vì vậy, bất cứ khi nào một con trỏ thông minh được gán cho một con trỏ khác, số tham chiếu nội bộ cộng với cộng. Và bất cứ khi nào đối tượng đi ra khỏi phạm vi, số tham chiếu trừ đi.

Con trỏ tự động, mặc dù trông tương tự, hoàn toàn khác với con trỏ thông minh. Đây là một lớp thuận tiện để phân bổ tài nguyên bất cứ khi nào một đối tượng con trỏ tự động đi ra khỏi phạm vi biến. Ở một mức độ nào đó, nó làm cho một con trỏ (bộ nhớ được cấp phát động) hoạt động tương tự như một biến ngăn xếp (được phân bổ tĩnh trong thời gian biên dịch).


2

Con trỏ thông minh là những nơi bạn không phải lo lắng về Phân bổ bộ nhớ, chia sẻ tài nguyên và chuyển giao.

Bạn rất có thể sử dụng các con trỏ này theo cách tương tự như bất kỳ phân bổ nào hoạt động trong Java. Trong java Garbage Collector thực hiện thủ thuật, trong khi trong Smart Pointers, thủ thuật được thực hiện bởi Dest phá.


1

Các câu trả lời hiện có là tốt nhưng không bao gồm những gì cần làm khi một con trỏ thông minh không phải là câu trả lời (đầy đủ) cho vấn đề bạn đang cố gắng giải quyết.

Trong số những điều khác (được giải thích tốt trong các câu trả lời khác) bằng cách sử dụng một con trỏ thông minh là một giải pháp khả thi cho Làm thế nào để chúng ta sử dụng một lớp trừu tượng như một kiểu trả về hàm? đã được đánh dấu là một bản sao của câu hỏi này. Tuy nhiên, câu hỏi đầu tiên để hỏi liệu có muốn chỉ định một lớp cơ sở trừu tượng (hoặc trên thực tế là bất kỳ) làm kiểu trả về trong C ++ là "bạn thực sự có ý gì?". Có một cuộc thảo luận tốt (với các tài liệu tham khảo thêm) về lập trình hướng đối tượng thành ngữ trong C ++ (và cách này khác với các ngôn ngữ khác) trong tài liệu của thư viện thùng chứa con trỏ boost. Tóm lại, trong C ++, bạn phải nghĩ về quyền sở hữu. Những con trỏ thông minh nào giúp bạn, nhưng không phải là giải pháp duy nhất hoặc luôn luôn là một giải pháp hoàn chỉnh (chúng không cung cấp cho bạn bản sao đa hình) và không phải lúc nào cũng là một giải pháp bạn muốn đưa ra trong giao diện của mình (và trả về chức năng nghe có vẻ khủng khiếp rất giống một giao diện). Nó có thể là đủ để trả lại một tài liệu tham khảo, ví dụ. Nhưng trong tất cả các trường hợp này (con trỏ thông minh, thùng chứa con trỏ hoặc đơn giản là trả về một tham chiếu), bạn đã thay đổi trả về từ một giá trị thành một dạng tham chiếu nào đó hoặc Boost.TypeErasure. Nếu bạn thực sự cần sao chép, bạn có thể cần thêm "thành ngữ" soạn sẵn hoặc vượt ra ngoài OOP thành ngữ (hoặc nói cách khác) trong C ++ sang đa hình chung hơn bằng các thư viện như Adobe Poly .

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.