Phân bổ động chỉ được yêu cầu khi thời gian sống của đối tượng phải khác với phạm vi được tạo trong (Điều này cũng giúp cho phạm vi nhỏ hơn khi lớn hơn) và bạn có một lý do cụ thể trong đó lưu trữ theo giá trị không công việc.
Ví dụ:
std::vector<int> *createVector(); // Bad
std::vector<int> createVector(); // Good
auto v = new std::vector<int>(); // Bad
auto result = calculate(/*optional output = */ v);
auto v = std::vector<int>(); // Good
auto result = calculate(/*optional output = */ &v);
Từ C ++ 11 trở đi, chúng ta đã std::unique_ptr
xử lý bộ nhớ được phân bổ, trong đó có quyền sở hữu bộ nhớ được phân bổ. std::shared_ptr
được tạo ra khi bạn phải chia sẻ quyền sở hữu. (bạn sẽ cần điều này ít hơn bạn mong đợi trong một chương trình tốt)
Tạo một cá thể trở nên thực sự dễ dàng:
auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11
C ++ 17 cũng cho biết thêm std::optional
có thể ngăn bạn yêu cầu phân bổ bộ nhớ
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
Ngay khi 'cá thể' đi ra khỏi phạm vi, bộ nhớ sẽ được dọn sạch. Chuyển quyền sở hữu cũng dễ dàng:
auto vector = std::vector<std::unique_ptr<Interface>>{};
auto instance = std::make_unique<Class>();
vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)
Vậy khi nào bạn vẫn cần new
? Hầu như không bao giờ từ C ++ 11 trở đi. Hầu hết các bạn sử dụng std::make_unique
cho đến khi bạn đạt đến điểm mà bạn đạt được một API chuyển quyền sở hữu thông qua các con trỏ thô.
auto instance = std::make_unique<Class>();
legacyFunction(instance.release()); // Ownership being transferred
auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr
Trong C ++ 98/03, bạn phải thực hiện quản lý bộ nhớ thủ công. Nếu bạn ở trong trường hợp này, hãy thử nâng cấp lên phiên bản mới hơn của tiêu chuẩn. Nếu bạn bị mắc kẹt:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
Hãy chắc chắn rằng bạn theo dõi quyền sở hữu một cách chính xác để không có bất kỳ rò rỉ bộ nhớ! Di chuyển ngữ nghĩa cũng không hoạt động.
Vậy, khi nào chúng ta cần malloc trong C ++? Lý do hợp lệ duy nhất sẽ là phân bổ bộ nhớ và khởi tạo nó sau thông qua vị trí mới.
auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
auto instance = new(instanceBlob)Class{}; // Initialize via constructor
instance.~Class(); // Destroy via destructor
std::free(instanceBlob); // Deallocate the memory
Mặc dù, những điều trên là hợp lệ, điều này cũng có thể được thực hiện thông qua một nhà điều hành mới. std::vector
là một ví dụ tốt cho việc này.
Cuối cùng, chúng tôi vẫn còn con voi trong phòng : C
. Nếu bạn phải làm việc với thư viện C nơi bộ nhớ được cấp phát trong mã C ++ và được giải phóng trong mã C (hoặc ngược lại), bạn buộc phải sử dụng malloc / miễn phí.
Nếu bạn ở trong trường hợp này, hãy quên các hàm ảo, hàm thành viên, lớp ... Chỉ cho phép các cấu trúc có POD trong đó.
Một số ngoại lệ cho các quy tắc:
- Bạn đang viết một thư viện chuẩn với các cấu trúc dữ liệu nâng cao trong đó malloc phù hợp
- Bạn phải phân bổ số lượng lớn bộ nhớ (Trong bản sao bộ nhớ của tệp 10 GB?)
- Bạn có công cụ ngăn bạn sử dụng các cấu trúc nhất định
- Bạn cần lưu trữ một loại không đầy đủ