2015-05-12 22 views
7

tôi khám phá chủ đề này trong Coliru với lệnh đầu vào sau:Tại sao std :: shared_ptr <T> = std :: unique_ptr <T[]> biên dịch, trong khi std :: shared_ptr <T[]> = std :: unique_ptr <T[]> thì không?

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out 

thử nghiệm này có thể được tìm thấy here, nhưng tôi đã đăng tải đoạn code dưới đây. Tôi đã sử dụng int trong ví dụ của mình vì đây là loại cơ bản.


#include <iostream> 
#include <memory> 

struct Foo{ 
    Foo() : 
    a_{0}, b_{1}, c_{-1}, combination_{0.5} {} 

    int 
     a_, 
     b_, 
     c_; 
    double 
     combination_; 
}; 

int main() 
{ 
    //int 
    // *unManagedArray = new int[16]; 
    std::unique_ptr<int[]> 
     uniqueArrayOrigin = std::make_unique<int[]>(16); 
    std::shared_ptr<int> 
      // works but needs call to new 
    // sharedSingleTest{unManagedArray, std::default_delete<int[]>{}}; 
      // works, does not require call to new 
     sharedSingleUnique = std::make_unique<int[]>(16);  
      // compilation error (conversion to non-scalar type) 
    // sharedSingleDerived = uniqueArrayOrigin;     

    // std::shared_ptr<int[]> 
       // compilation errors 
    //  sharedArrayTest{unManagedArray, std::default_delete<int[]>{}}; 
       // compilation error (conversion to non-scalar type) 
    //  sharedArrayUnique = std::make_unique<int[]>(16); 
       // compilation error (conversion to non-scalar type) 
    //  sharedArrayDerived = uniqueArrayOrigin; 

    std::shared_ptr<Foo> 
      // works: specified overload of operator= for shared_ptr 
     nonArrayTest = std::make_unique<Foo>(); 

    std::cout << "done!\n"; 
} 

Tôi đã nhìn quanh trên SO cho câu trả lời, nhưng chỉ bật lên references đến việc thực hiện std::shared_ptr không có một chuyên môn hóa, và điều này chủ yếu là bởi vì không ai làm phiền để cho một thích hợp đề xuất với ủy ban tiêu chuẩn về đề tài này.

Tôi tò mò, bởi vì tôi sẽ giải thích tình trạng quá tải thứ 4 của operator=, std::shared_ptr<T[]>.operator=(std::unique_ptr<T[], Deleter>&&) trên cppreference để cho biết rằng cú pháp như thế là legal-- T[]T[] là cùng loại không phụ thuộc vào trạng thái của các chuyên ngành với nhiều loại mảng cho std::shared_ptr, sau khi tất cả . Ngoài ra, cú pháp này chỉ xuất hiện để hoạt động trên sản phẩm của std::make_unique<T[]> và không phải là đối tượng con trỏ duy nhất, điều này đi ngược lại với sự hiểu biết của tôi về chủ đề - không nên thực hiện cuộc gọi một cách hiệu quả. và đối tượng kia, di chuyển một đối tượng vừa được tạo ra? Tôi sẽ mong đợi sự khác biệt duy nhất giữa chúng sẽ là không hợp lệ std::unique_ptr<T[]> sau khi gọi hàm trong trường hợp đầu tiên. Là một lưu ý phụ, tôi giả định rằng vì có cách xây dựng một mảng được phân bổ động vào một shared_ptr mà không yêu cầu sử dụng new, tôi nên sử dụng nó với cuộc gọi lộn xộn và không an toàn hơn đến new T[N] ?

tl; dr:

  1. operator= không làm việc ở tất cả giữa std::shared_ptr<T[]>std::unique_ptr<T[]> dù tôi mong chờ nó để làm việc. Tại sao?
  2. Nếu có bất kỳ điều gì, tôi muốn chuyển đổi loại từ T[] thành T thành nguồn lỗi biên dịch giữa các con trỏ duy nhất và được chia sẻ. Tại sao điều này hoạt động?
  3. operator= hoạt động giữa std::shared_ptr<T>std::make_unique<T[]> nhưng không phải std::unique_ptr<T[]>. Tại sao?
  4. Tôi có đúng để giả định trong trường hợp yêu cầu mảng được phân bổ động, được chia sẻ không, nhưng tôi không muốn sử dụng tăng hoặc véc tơ (lý do bên dưới), tôi nên gọi operator= std::make_unique<T[]>(N)?

Tại sao tôi không sử dụng?

  • Boost: không được chấp thuận cho sử dụng được nêu ra trong công ty của tôi, và tôi không biết khi nào hoặc nếu tôi sẽ nhận được sự chấp thuận để sử dụng nó.
  • Mảng: Tôi phải xác định kích thước của mảng này khi chạy.
  • Vectơ: Tôi đang làm việc trên hệ thống xử lý tín hiệu thời gian thực và muốn tránh sự chú ý thêm con trỏ. Tôi cũng cố gắng tránh các thư viện không liên quan trong các tệp tiêu đề của tôi (đây là thông tin liên lạc giữa đọc và viết hệ thống con) Tuy nhiên, cuối cùng tôi đã chọn tối ưu hóa sau này, nếu nó quan trọng (tối ưu hóa sớm ...) và cắn đạn. Câu hỏi vẫn còn, mặc dù.
+4

Hiện tại, 'std :: shared_ptr' không hỗ trợ mảng. –

+0

Để làm rõ: Nó không chỉ đơn thuần là trường hợp một chuyên môn cho các loại mảng không tồn tại, nhưng 'std :: shared_ptr' chủ động không hỗ trợ mảng? Tôi đã giả định rằng việc thiếu chuyên môn có nghĩa là nó hoạt động trên các loại mảng như chúng là bất kỳ loại nào khác. – jaggedSpire

Trả lời

5

§20.8.2.2.1/28:

template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r); 

Ghi chú: constructor này sẽ không tham gia vào giải quyết tình trạng quá tải trừ unique_ptr<Y, D>::pointer là mui trần để T*.

Tuy nhiên, unique_ptr<U[]>::pointer thực sự là U*, trong khi shared_ptr<U[]> 's T*U(*)[]; Và U* không thể được chuyển đổi thành U(*)[], do đó tình trạng quá tải không bao giờ được xem xét.

+0

@Yakk Vì vậy, vì hành vi của một 'shared_ptr' không được chỉ định của kiểu' T [] 'không phải là những gì tôi có thể mong đợi, tốt nhất là chỉ đơn giản coi chúng đơn giản là không được hỗ trợ như T.C. cho biết, thay vì chỉ đơn giản là thiếu một vài bổ sung tốt đẹp cho chức năng? – jaggedSpire

+1

@jaggedSpire Chính xác. Cũng xem xét rằng 'shared_ptr' không bao giờ gọi' delete [] '. – Columbo

+0

Tại sao nó sẽ không gọi deleter thích hợp khi được cung cấp với deleter từ đối tượng 'unique_ptr ' chuyên biệt? Ngoài ra, tôi có thể hỏi thêm tại sao có sự khác biệt về chức năng trong việc xây dựng 'shared_ptr ' trong câu hỏi từ 'unique_ptr ' hiện tại và từ sản phẩm của 'make_unique '? – jaggedSpire

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