Đó là vì std::shared_ptr
thực hiện kiểu tẩy xoá, trong khi std::unique_ptr
không.
Kể từ std::shared_ptr
thực hiện kiểu tẩy xoá, nó cũng hỗ trợ khác bất động sản hấp dẫn, tức. số điện thoại không phải cần loại số deleter làm đối số loại mẫu cho mẫu lớp học. Nhìn vào tờ khai của họ:
template<class T,class Deleter = std::default_delete<T> >
class unique_ptr;
trong đó có Deleter
như tham số kiểu, trong khi
template<class T>
class shared_ptr;
không có nó.
Bây giờ, câu hỏi đặt ra là, tại sao shared_ptr
triển khai loại xóa? Vâng, nó làm như vậy, bởi vì nó có hỗ trợ tham chiếu, và để hỗ trợ điều này, nó phải cấp phát bộ nhớ từ heap và vì nó phải cấp phát bộ nhớ, nó đi thêm một bước nữa và thực hiện loại xóa — cũng cần phân bổ đống. Vì vậy, về cơ bản nó chỉ là cơ hội!
Bởi vì kiểu tẩy xoá, std::shared_ptr
là khả năng hỗ trợ hai điều:
- Nó có thể lưu trữ các đối tượng của bất kỳ loại như
void*
, nhưng nó vẫn có thể xóa các đối tượng trên phá hủy đúng bằng một cách chính xác gọi destructor của họ.
- Loại deleter không được chuyển làm đối số kiểu cho mẫu lớp, có nghĩa là tự do một chút mà không ảnh hưởng đến an toàn loại.
Được rồi. Đó là tất cả về cách std::shared_ptr
hoạt động.
Bây giờ câu hỏi là, có thể std::unique_ptr
lưu trữ các đối tượng làvoid*
? Vâng, câu trả lời là, có — miễn là bạn vượt qua một deleter phù hợp làm đối số.Dưới đây là một trong những cuộc biểu tình như vậy:
int main()
{
auto deleter = [](void const * data) {
int const * p = static_cast<int const*>(data);
std::cout << *p << " located at " << p << " is being deleted";
delete p;
};
std::unique_ptr<void, decltype(deleter)> p(new int(959), deleter);
} //p will be deleted here, both p ;-)
Output (online demo):
959 located at 0x18aec20 is being deleted
Bạn hỏi một câu hỏi rất thú vị trong bình luận:
Trong trường hợp của tôi, tôi sẽ cần một loại xóa deleter, nhưng có vẻ như có thể là tốt (với chi phí của một số phân bổ đống). Về cơ bản, điều này có nghĩa là có thực sự là một điểm thích hợp cho một loại 3 của con trỏ thông minh: một con trỏ thông minh độc quyền sở hữu với loại tẩy xoá.
mà @Steve Jessop đề nghị các giải pháp sau đây,
Tôi chưa bao giờ thực sự cố gắng này, nhưng có lẽ bạn có thể đạt được điều đó bằng cách sử dụng một cách phù hợp std::function
như các loại deleter với unique_ptr
? Giả sử rằng thực sự hoạt động sau đó bạn đã hoàn thành, độc quyền sở hữu và một deleter loại xóa.
Tiếp theo đề nghị này, tôi thực hiện điều này,
using deleter_t = std::function<void(void *)>;
using unique_void_ptr = std::unique_ptr<void, deleter_t>;
template<typename T>
auto deleter(void const * data) -> void
{
T const * p = static_cast<T const*>(data);
std::cout << "{" << *p << "} located at [" << p << "] is being deleted.\n";
delete p;
}
template<typename T>
auto unique_void(T * ptr) -> unique_void_ptr
{
return unique_void_ptr(ptr, &deleter<T>);
}
int main()
{
auto p1 = unique_void(new int(959));
auto p2 = unique_void(new double(595.5));
auto p3 = unique_void(new std::string("Hello World"));
}
Output (online demo):
{Hello World} located at [0x2364c60] is being deleted.
{595.5} located at [0x2364c40] is being deleted.
{959} located at [0x2364c20] is being deleted.
Hy vọng rằng sẽ giúp.
Câu trả lời hay, +1. Nhưng bạn có thể làm cho nó tốt hơn bằng cách đề cập rõ ràng rằng một 'std :: unique_ptr' vẫn có thể bằng cách cung cấp một 'D' phù hợp. –
Angew
@Angrew: Đẹp nhất, bạn đã tìm thấy câu hỏi cơ bản thực sự không được viết trong câu hỏi của tôi;) –
@Nawaz: Cảm ơn bạn. Trong trường hợp của tôi, tôi sẽ cần một deleter loại xóa, nhưng có vẻ như có thể là tốt (với chi phí của một số phân bổ đống).Về cơ bản, điều này có nghĩa là có thực sự là một điểm thích hợp cho một loại 3 của con trỏ thông minh: một con trỏ thông minh độc quyền sở hữu với loại tẩy xoá? –