Hãy tổ chức một số công dụng và gotchas sử dụng định dạng Q & A.
(. Tất nhiên, là một thông minh con trỏ , không cần để xóa một cách rõ ràng trong lớp destructor chứa)
Q2: Tuyệt vời! Không cần phá hủy rõ ràng, không có chi phí std::shared_ptr
(triết lý điển hình C++: "Chúng tôi không thanh toán cho những thứ chúng tôi không sử dụng"), di chuyển máy móc ngữ nghĩa đã được triển khai!
Tuy nhiên, tôi có một vấn đề: lớp học của tôi Component
có một quá tải xây dựng mà mất một số tham số mà tôi cần phải tính toán trong mã nhà xây dựng trước khi tạo ra Component
trường hợp.Tôi đã cố gắng sử dụng bình thường operator=
assigment trong constructor để gán mới được tạo ra Component
đến unique_ptr
, nhưng tôi có một thông báo lỗi:
X::X()
{
....
const int param = CalculateCoolParameter();
// This assignment fails:
m_pComponent = new Component(param); // <---- Error pointing to '=' here
^--- error
}
A2: OK, có lẽ bạn đã mong đợi một tình trạng quá tải operator=
phát hành trước đó thuộc sở hữu con trỏ (nếu có) và gán cho con mới tạo.
Thật không may, không quá tải.
Tuy nhiên, phương thức std::unique_ptr::reset()
sẽ làm!
m_pComponent.reset(new Component(param));
Q3: Hey! Điều này unique_ptr
là thực sự mát mẻ! Tôi thích thực tế là nó thông minh, nó tự động di chuyển và không mang lại chi phí.
Vì vậy, tôi muốn sử dụng nó để lưu trữ mảng được phân bổ động của một số kích thước cố định (được tính tại thời gian chạy) thay vì sử dụng std::vector
(trong phần mã này muốn trả tiền cho chi phí std:vector
, vì tôi không muốn tất cả các tính năng tự động thay đổi kích thước std::vector
, sao chép sâu, v.v ...).
tôi đã cố gắng một cái gì đó như thế này:
const size_t count = GetComponentsCount();
unique_ptr<Component> components(new Component[count]);
Nó biên dịch tốt, nhưng tôi lưu ý rằng ~Component
destructor được gọi là chỉ lần, thay vào đó tôi mong đợi count
cuộc gọi destructor! Có gì sai ở đây?
A3: Vấn đề là, với cú pháp trên, std::unique_ptr
sử dụng delete
để giải phóng các đối tượng được phân bổ. Nhưng kể từ khi chúng được phân bổ bằng cách sử dụng new[]
, cuộc gọi dọn sạch thích hợp là delete[]
(không phải đơn giản delete
không có dấu ngoặc vuông).
Để khắc phục điều đó và để hướng dẫn unique_ptr
để sử dụng đúng cách delete[]
giải phóng nguồn lực, cú pháp sau đây phải được sử dụng:
unique_ptr<Component[]> components(new Components[count]);
// ^^
//
// Note brackets "[]" after the first occurrence of "Component"
// in unique_ptr template argument.
//
Q4: Đó là tuyệt vời! Nhưng tôi có thể sử dụng unique_ptr
cũng trong trường hợp trong đó các mã nguồn phát hành không được thực hiện bằng C thường ++ delete
(hoặc delete[]
), nhưng thay vì sử dụng một số chức năng dọn dẹp tùy chỉnh, như fclose()
cho các tập tin C <stdio.h>
(mở với fopen()
), hoặc CloseHandle()
cho tập tin Win32 HANDLE
s (được tạo bằng cách sử dụng CreateFile()
)?
A4: Đó là chắc chắn có thể: bạn có thể chỉ định một deleter tùy chỉnh cho std::unique_ptr
.
ví dụ::
//
// Custom deleter function for FILE*: fclose().
//
std::unique_ptr<FILE, // <-- the wrapped raw pointer type: FILE*
int(*)(FILE*)> // <-- the custom deleter type: fclose() prototype
myFile(fopen("myfile", "rb"), // <-- resource (FILE*) is returned by fopen()
fclose); // <-- the deleter function: fclose()
//
// Custom deleter functor for Win32 HANDLE: calls CloseHandle().
//
struct CloseHandleDeleter
{
// The following pointer typedef is required, since
// the raw resource is HANDLE (not HANDLE*).
typedef HANDLE pointer;
// Custom deleter: calls CloseHandle().
void operator()(HANDLE handle) const
{
CloseHandle(handle);
}
};
std::unique_ptr<HANDLE, CloseHandleDeleter> myFile(CreateFile(....));
FWIW, bạn sẽ trả cho các tính năng vectơ bạn không sử dụng? (gợi ý: không có gì) –
Ít nhất từ dấu chân bộ nhớ, 'std :: vector' có thể sử dụng 3 con trỏ, thay vào đó' unique_ptr' chỉ một. –
A2: một giải pháp đẹp hơn, nếu có thể, là có một phương pháp làm phép đo tốc độ và trả về tiêu chuẩn :: unique_ptr, sau đó sử dụng quyền đó trong danh sách khởi tạo. – stijn