2014-09-18 18 views
69

cplusplus.com shared_ptr page gọi ra sự khác biệt giữa một số trốngstd::shared_ptrnullshared_ptr. Các cppreference.com page không rõ ràng gọi ra sự khác biệt, nhưng sử dụng cả hai "trống rỗng" và so sánh với nullptr trong mô tả của nó về hành vi std::shared_ptr.Sự khác nhau giữa một rỗng và một std null :: shared_ptr trong C++ là gì?

Có sự khác biệt giữa giá trị rỗng và không rỗng shared_ptr không? Có bất kỳ trường hợp sử dụng cho các con trỏ hành vi hỗn hợp như vậy? Có một số không rỗng rỗng shared_ptr thậm chí có ý nghĩa không? Có bao giờ sẽ là một trường hợp trong việc sử dụng bình thường (tức là nếu bạn không xây dựng một cách rõ ràng), nơi bạn có thể kết thúc với một rỗng-nhưng-không null shared_ptr?

Và bất kỳ câu trả lời nào trong số này có thay đổi nếu bạn đang sử dụng phiên bản Tăng cường thay vì phiên bản C++ 11 không?

Trả lời

72

Đó là một góc lạ của hành vi shared_ptr. Nó có một nhà xây dựng cho phép bạn thực hiện một shared_ptr rằng sở hữu một cái gì đó và điểm để cái gì khác:

template< class Y > 
shared_ptr(const shared_ptr<Y>& r, T *ptr); 

Các shared_ptr xây dựng bằng này constructor cổ phiếu sở hữu với r, nhưng điểm để bất cứ điều gì ptr điểm đến (ví dụ: gọi get() hoặc operator->() sẽ trả lại ptr). Điều này thuận tiện cho các trường hợp trong đó ptr trỏ đến một đối tượng phụ (ví dụ: thành viên dữ liệu) của đối tượng thuộc sở hữu của r.

Trang bạn liên kết gọi là shared_ptr sở hữu không có gì trống, và một shared_ptr trỏ đến không có gì (ví dụ, có get() == nullptr) rỗng. (Rỗng được sử dụng theo nghĩa này theo tiêu chuẩn; null không.) Bạn có thể tạo một số không rỗng nhưng không rỗng shared_ptr, nhưng nó sẽ không hữu ích lắm. An rỗng-nhưng-không-null shared_ptr về cơ bản là một con trỏ không sở hữu, có thể được sử dụng để làm một số điều kỳ lạ như passing a pointer to something allocated on the stack to a function expecting a shared_ptr (nhưng tôi muốn đề nghị đấm bất cứ ai đặt shared_ptr bên trong API đầu tiên).

boost::shared_ptr cũng has this constructor, mà họ gọi là hàm tạo răng cưa.

+7

Worth chú ý: ** C++ 11 § 20.7.2.2.1 (p16) ** "Lưu ý: Hàm khởi tạo này cho phép tạo một cá thể' shared_ptr' rỗng với một con trỏ được lưu trữ không NULL. " Cũng đáng nói đến lưu ý trước (p15), "Để tránh khả năng của một con trỏ lơ lửng, người sử dụng của constructor này phải đảm bảo rằng' p' vẫn còn hợp lệ ít nhất cho đến khi nhóm sở hữu 'r' bị hủy." Một công trình hiếm khi được sử dụng thực sự. – WhozCraig

+0

@Cubbi Một 'shared_ptr' có' get() 'trả về' nullptr' * không * so sánh bằng 'nullptr' bất kể nó có sở hữu gì không. –

+3

Một 'shared_ptr's * có thể * hữu ích, để đảm bảo một số hàm được thực hiện khi tất cả các con trỏ sở hữu hết phạm vi (ngay cả trong trường hợp ngoại lệ!). Không chắc chắn, cho dù bây giờ có một lớp học đặc biệt cho việc này. – coldfix

2

Có sự khác biệt nào giữa shared_ptr trống và không?

Trống shared_ptr không có khối điều khiển và số lượng sử dụng của nó được coi là 0. Bản sao trống shared_ptr là một ô trống khác shared_ptr. Cả hai đều là riêng biệt shared_ptr s không chia sẻ khối điều khiển chung vì chúng không có. Làm trống shared_ptr có thể được xây dựng với hàm tạo mặc định hoặc với hàm tạo mất nullptr.

Không trống rỗng shared_ptr có khối điều khiển có thể được chia sẻ với shared_ptr s khác.Bản sao không trống rỗng shared_ptrshared_ptr chia sẻ cùng một khối điều khiển như ban đầu shared_ptr vì vậy số lượng sử dụng không phải là 0,Có thể nói rằng tất cả các bản sao của shared_ptr đều chia sẻ cùng một số nullptr. rỗng không trống shared_ptr thể được xây dựng với con trỏ null loại đối tượng (không nullptr)

Dưới đây là ví dụ:

#include <iostream> 
#include <memory> 

int main() 
{ 
    std::cout << "std::shared_ptr<int> ptr1:" << std::endl; 
    { 
     std::shared_ptr<int> ptr1; 
     std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl; 
     std::shared_ptr<int> ptr2 = ptr1; 
     std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;   
     std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl; 
    } 
    std::cout << std::endl; 

    std::cout << "std::shared_ptr<int> ptr1(nullptr):" << std::endl; 
    { 
     std::shared_ptr<int> ptr1(nullptr); 
     std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl; 
     std::shared_ptr<int> ptr2 = ptr1; 
     std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;   
     std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl; 
    } 
    std::cout << std::endl; 

    std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl; 
    { 
     std::shared_ptr<int> ptr1(static_cast<int*>(nullptr)); 
     std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl; 
     std::shared_ptr<int> ptr2 = ptr1; 
     std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;   
     std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl; 
    } 
    std::cout << std::endl; 

    return 0; 
} 

Nó ra:

std::shared_ptr<int> ptr1: 
    use count before copying ptr: 0 
    use count after copying ptr: 0 
    ptr1 is null 

std::shared_ptr<int> ptr1(nullptr): 
    use count before copying ptr: 0 
    use count after copying ptr: 0 
    ptr1 is null 

std::shared_ptr<int> ptr1(static_cast<int*>(nullptr)) 
    use count before copying ptr: 1 
    use count after copying ptr: 2 
    ptr1 is null 

http://coliru.stacked-crooked.com/a/54f59730905ed2ff

+0

Tôi nghĩ rằng câu trả lời này tốt hơn tại sao chúng ta phải kiểm tra null trong deleter tùy chỉnh của shared_ptr. [Liệu nó có ý nghĩa để kiểm tra nullptr trong deleter tùy chỉnh của shared_ptr?] (Https://stackoverflow.com/questions/42962515/does-it-make-sense-to-check-for-nullptr-in-custom-deleter -of-shared-ptr/42962962) –

Các vấn đề liên quan