Có sử dụng cho unique_ptr với mảng không?


238

std::unique_ptr có hỗ trợ cho mảng, ví dụ:

std::unique_ptr<int[]> p(new int[10]);

Nhưng nó có cần thiết không? có lẽ nó là thuận tiện hơn để sử dụng std::vectorhoặc std::array.

Bạn có tìm thấy bất kỳ sử dụng cho cấu trúc đó?


6
Để đầy đủ, tôi nên chỉ ra rằng không có std::shared_ptr<T[]>, nhưng nên có, và có lẽ sẽ có trong C ++ 14 nếu bất cứ ai có thể bị làm phiền để viết một đề xuất. Trong lúc này, luôn luôn có boost::shared_array.
Bút danh

13
std::shared_ptr<T []> hiện đang ở c ++ 17.

Bạn có thể tìm thấy nhiều cách để làm bất cứ điều gì trên máy tính. Cấu trúc này có sử dụng, đặc biệt là trong một đường dẫn nóng, bởi vì nó xóa bỏ chi phí hoạt động của container nếu bạn biết chính xác cách nhắm mục tiêu mảng của mình. Ngoài ra, nó tạo ra các mảng ký tự mà không có bất kỳ nghi ngờ nào về việc lưu trữ liền kề.
kevr

Câu trả lời:


256

Một số người không có sự sang trọng trong việc sử dụng std::vector, ngay cả với người cấp phát. Một số người cần một mảng kích thước động, như vậy std::arraylà ra. Và một số người nhận được mảng của họ từ mã khác được biết là trả về một mảng; và mã đó sẽ không được viết lại để trả về một vectorhoặc một cái gì đó.

Bằng cách cho phép unique_ptr<T[]>, bạn phục vụ những nhu cầu đó.

Tóm lại, bạn sử dụng unique_ptr<T[]>khi bạn cần . Khi các lựa chọn thay thế đơn giản là sẽ không làm việc cho bạn. Đó là một công cụ của phương sách cuối cùng.


27
@NoSenseEtAl: Tôi không chắc phần nào trong "một số người không được phép làm điều đó" khiến bạn lảng tránh. Một số dự án có các yêu cầu rất cụ thể và trong số đó có thể là "bạn không được sử dụng vector". Bạn có thể tranh luận liệu đó có phải là những yêu cầu hợp lý hay không, nhưng bạn không thể phủ nhận rằng chúng tồn tại .
Nicol Bolas

21
Không có lý do nào trên thế giới tại sao một người nào đó sẽ không thể sử dụng std::vectornếu họ có thể sử dụng std::unique_ptr.
Miles Rout

66
đây là một lý do để không sử dụng vector: sizeof (std :: vector <char>) == 24; sizeof (std :: unique_ptr <char []>) == 8
Arvid

13
@DanNissenbaum Những dự án này tồn tại. Một số ngành công nghiệp đang được kiểm tra rất kỹ lưỡng, chẳng hạn như hàng không hoặc quốc phòng, thư viện tiêu chuẩn bị giới hạn bởi vì rất khó để xác minh và chứng minh rằng nó đúng với bất kỳ cơ quan quản lý nào đặt ra các quy định. Bạn có thể lập luận rằng thư viện tiêu chuẩn đã được kiểm tra tốt và tôi sẽ đồng ý với bạn nhưng bạn và tôi không đưa ra các quy tắc.
Emily L.

16
@DanNissenbaum Ngoài ra, một số hệ thống thời gian thực cứng không được phép sử dụng cấp phát bộ nhớ động vì độ trễ của một cuộc gọi hệ thống có thể không bị ràng buộc về mặt lý thuyết và bạn không thể chứng minh hành vi thời gian thực của chương trình. Hoặc giới hạn có thể quá lớn sẽ phá vỡ giới hạn WCET của bạn. Mặc dù không áp dụng ở đây, vì họ sẽ không sử dụng unique_ptrnhưng những loại dự án đó thực sự tồn tại.
Emily L.

124

Có sự đánh đổi, và bạn chọn giải pháp phù hợp với những gì bạn muốn. Off đỉnh đầu của tôi:

Kích thước ban đầu

  • vectorunique_ptr<T[]>cho phép kích thước được chỉ định trong thời gian chạy
  • array chỉ cho phép kích thước được chỉ định tại thời gian biên dịch

Thay đổi kích thước

  • arrayunique_ptr<T[]>không cho phép thay đổi kích thước
  • vector làm

Lưu trữ

  • vectorunique_ptr<T[]>lưu trữ dữ liệu bên ngoài đối tượng (thường là trên heap)
  • array lưu trữ dữ liệu trực tiếp trong đối tượng

Đang sao chép

  • arrayvectorcho phép sao chép
  • unique_ptr<T[]> không cho phép sao chép

Hoán đổi / di chuyển

  • vectorunique_ptr<T[]>có O (1) thời gian swapvà các hoạt động di chuyển
  • arraycó O (n) thời gian swapvà các hoạt động di chuyển, trong đó n là số phần tử trong mảng

Con trỏ / tham chiếu / iterator không hợp lệ

  • array đảm bảo các con trỏ, tham chiếu và các trình vòng lặp sẽ không bao giờ bị vô hiệu trong khi đối tượng đang hoạt động, ngay cả trên swap()
  • unique_ptr<T[]>không có vòng lặp; con trỏ và tham chiếu chỉ bị vô hiệu bởi swap()trong khi đối tượng đang sống. (Sau khi hoán đổi, các con trỏ trỏ vào mảng mà bạn đã tráo đổi, vì vậy chúng vẫn "hợp lệ" theo nghĩa đó.)
  • vector có thể làm mất hiệu lực con trỏ, tham chiếu và lặp trong bất kỳ sự phân bổ lại nào (và cung cấp một số đảm bảo rằng việc tái phân bổ chỉ có thể xảy ra đối với các hoạt động nhất định).

Khả năng tương thích với các khái niệm và thuật toán

  • arrayvectorlà cả hai Container
  • unique_ptr<T[]> không phải là một container

Tôi phải thừa nhận, đây có vẻ là một cơ hội cho một số tái cấu trúc với thiết kế dựa trên chính sách.


1
Tôi không chắc tôi hiểu ý của bạn trong bối cảnh vô hiệu hóa con trỏ . Đây có phải là về con trỏ đến chính các đối tượng, hoặc con trỏ đến các yếu tố? Hay cái gì khác? Loại bảo đảm nào bạn nhận được từ một mảng mà bạn không nhận được từ một vectơ?
jogojapan

3
Giả sử rằng bạn có một trình vòng lặp, một con trỏ hoặc tham chiếu đến một phần tử của a vector. Sau đó, bạn tăng kích thước hoặc công suất của vectornó để nó buộc phải phân bổ lại. Sau đó, trình vòng lặp, con trỏ hoặc tham chiếu đó không còn trỏ đến phần tử đó của vector. Đây là những gì chúng tôi có nghĩa là "vô hiệu". Vấn đề này không xảy ra array, bởi vì không có "tái phân bổ". Trên thực tế, tôi chỉ nhận thấy một chi tiết với điều đó, và tôi đã chỉnh sửa nó cho phù hợp.
Bút danh

1
Ok, không thể có sự vô hiệu do kết quả của việc tái phân bổ trong một mảng hoặc unique_ptr<T[]>vì không có sự phân bổ lại. Nhưng tất nhiên, khi mảng vượt quá phạm vi, con trỏ tới các phần tử cụ thể sẽ vẫn bị vô hiệu.
jogojapan

Có, tất cả các cược được tắt nếu đối tượng không còn sống.
Bút danh

1
@rubenvb Chắc chắn bạn có thể, nhưng bạn không thể (nói) sử dụng phạm vi dựa trên phạm vi trực tiếp. Ngẫu nhiên, không giống như bình thường T[], kích thước (hoặc thông tin tương đương) phải được treo xung quanh đâu đó operator delete[]để phá hủy chính xác các phần tử của mảng. Thật tuyệt nếu lập trình viên có quyền truy cập vào đó.
Bút danh

73

Một lý do bạn có thể sử dụng unique_ptrlà nếu bạn không muốn trả chi phí thời gian chạy của việc khởi tạo giá trị mảng.

std::vector<char> vec(1000000); // allocates AND value-initializes 1000000 chars

std::unique_ptr<char[]> p(new char[1000000]); // allocates storage for 1000000 chars

Hàm std::vectortạo và std::vector::resize()sẽ khởi tạo giá trị T- nhưng newsẽ không làm điều đó nếu Tlà POD.

Xem các đối tượng khởi tạo giá trị trong C ++ 11 và std :: vector constructor

Lưu ý rằng vector::reserveđây không phải là một thay thế ở đây: Truy cập con trỏ thô sau std :: vector :: reserved có an toàn không?

Đó là cùng một lý do một lập trình viên C có thể chọn mallochơn calloc.



@Ruslan Trong giải pháp được liên kết, các phần tử của mảng động vẫn được khởi tạo giá trị, nhưng khởi tạo giá trị không làm gì cả. Tôi đồng ý rằng một trình tối ưu hóa không nhận ra rằng không làm gì 1000000 lần có thể được thực hiện bởi không có mã nào là không đáng, nhưng người ta có thể không muốn phụ thuộc vào tối ưu hóa này.
Marc van Leeuwen

Tuy nhiên, một khả năng khác là cung cấp cho std::vectormột bộ cấp phát tùy chỉnh để tránh việc xây dựng các loại std::is_trivially_default_constructiblevà phá hủy các đối tượng std::is_trivially_destructible, mặc dù điều này vi phạm tiêu chuẩn C ++ (vì các loại đó không được khởi tạo mặc định).
Walter

Cũng std::unique_ptrkhông cung cấp bất kỳ kiểm tra ràng buộc nào trái với rất nhiều std::vectortriển khai.
diapir

30

An std::vectorcó thể được sao chép xung quanh, trong khi unique_ptr<int[]>cho phép thể hiện quyền sở hữu duy nhất của mảng. std::arraymặt khác, yêu cầu kích thước được xác định tại thời điểm biên dịch, có thể là không thể trong một số trường hợp.


2
Chỉ vì một cái gì đó có thể được sao chép xung quanh không có nghĩa là nó phải như vậy.
Nicol Bolas

4
@NicolBolas: Tôi không hiểu. Người ta có thể muốn ngăn chặn điều đó vì lý do tương tự tại sao người ta sẽ sử dụng unique_ptrthay vì shared_ptr. Tui bỏ lỡ điều gì vậy?
Andy Prowl

4
unique_ptrkhông chỉ ngăn ngừa lạm dụng tình cờ. Nó cũng nhỏ hơn và chi phí thấp hơn shared_ptr. Vấn đề là, mặc dù thật tuyệt khi có ngữ nghĩa trong một lớp ngăn chặn "lạm dụng", đó không phải là lý do duy nhất để sử dụng một loại cụ thể. Và vectorhữu ích hơn nhiều khi lưu trữ mảng hơn unique_ptr<T[]>, nếu không có lý do nào khác ngoài thực tế là nó có kích thước .
Nicol Bolas

3
Tôi nghĩ rằng tôi đã làm rõ vấn đề: có nhiều lý do khác để sử dụng một loại cụ thể hơn thế. Cũng giống như có nhiều lý do để thích vectorhơn unique_ptr<T[]>nơi có thể, thay vì chỉ nói, "bạn không thể sao chép nó" và do đó chọn unique_ptr<T[]>khi bạn không muốn sao chép. Ngăn chặn ai đó làm điều sai trái không nhất thiết là lý do quan trọng nhất để chọn một lớp học.
Nicol Bolas

8
std::vectorcó nhiều chi phí hơn a std::unique_ptr- nó sử dụng ~ 3 con trỏ thay vì ~ 1. std::unique_ptrchặn sao chép xây dựng nhưng cho phép di chuyển xây dựng, nếu về mặt ngữ nghĩa, dữ liệu bạn đang làm việc chỉ có thể được di chuyển nhưng không được sao chép, lây nhiễm classdữ liệu có chứa. Có một hoạt động trên dữ liệu không hợp lệ thực sự làm cho lớp container của bạn trở nên tồi tệ hơn và "chỉ không sử dụng nó" sẽ không rửa sạch mọi tội lỗi. Phải đặt mọi trường hợp của bạn std::vectorvào một lớp mà bạn vô hiệu hóa thủ công movelà một vấn đề đau đầu. std::unique_ptr<std::array>có một size.
Yakk - Adam Nevraumont

22

Scott Meyers có điều này để nói trong C ++ hiện đại hiệu quả

Sự tồn tại của std::unique_ptrđối với mảng nên chỉ quan tâm đến trí tuệ đối với bạn, bởi vì std::array, std::vector, std::stringhầu như lúc nào cũng lựa chọn cấu trúc dữ liệu tốt hơn so với mảng thô. Về tình huống duy nhất tôi có thể hình dung khi nào std::unique_ptr<T[]>sẽ có ý nghĩa khi bạn đang sử dụng API giống như C trả về một con trỏ thô cho một mảng heap mà bạn cho là quyền sở hữu.

Tôi nghĩ rằng câu trả lời của Charles Salvia có liên quan mặc dù: đó std::unique_ptr<T[]>là cách duy nhất để khởi tạo một mảng trống có kích thước không được biết đến tại thời điểm biên dịch. Scott Meyers sẽ nói gì về động lực này khi sử dụng std::unique_ptr<T[]>?


4
Có vẻ như anh ta chỉ đơn giản là không hình dung ra một vài trường hợp sử dụng, cụ thể là bộ đệm có kích thước cố định nhưng không xác định tại thời điểm biên dịch và / hoặc bộ đệm mà chúng tôi không cho phép sao chép. Cũng có hiệu quả là một lý do có thể để thích nó hơn vector stackoverflow.com/a/24852984/2436175 .
Antonio

17

Trái ngược với std::vectorstd::array, std::unique_ptrcó thể sở hữu một con trỏ NULL.
Điều này rất hữu ích khi làm việc với các API C mong đợi một mảng hoặc NULL:

void legacy_func(const int *array_or_null);

void some_func() {    
    std::unique_ptr<int[]> ptr;
    if (some_condition) {
        ptr.reset(new int[10]);
    }

    legacy_func(ptr.get());
}

10

Tôi đã sử dụng unique_ptr<char[]>để thực hiện một nhóm bộ nhớ preallocated được sử dụng trong một công cụ trò chơi. Ý tưởng là cung cấp các nhóm bộ nhớ preallocated được sử dụng thay vì phân bổ động để trả về kết quả yêu cầu va chạm và các thứ khác như vật lý hạt mà không phải phân bổ / bộ nhớ trống ở mỗi khung. Nó khá thuận tiện cho loại kịch bản này khi bạn cần nhóm bộ nhớ để phân bổ các đối tượng có thời gian sử dụng hạn chế (thường là một, 2 hoặc 3 khung hình) không yêu cầu logic phá hủy (chỉ phân bổ bộ nhớ).


9

Có thể tìm thấy một mẫu chung trong một số lệnh gọi Windows Win32 API , trong đó việc sử dụng std::unique_ptr<T[]>có thể có ích, ví dụ: khi bạn không biết chính xác bộ đệm đầu ra sẽ lớn như thế nào khi gọi một số API Win32 (sẽ ghi một số dữ liệu bên trong bộ đệm đó):

// Buffer dynamically allocated by the caller, and filled by some Win32 API function.
// (Allocation will be made inside the 'while' loop below.)
std::unique_ptr<BYTE[]> buffer;

// Buffer length, in bytes.
// Initialize with some initial length that you expect to succeed at the first API call.
UINT32 bufferLength = /* ... */;

LONG returnCode = ERROR_INSUFFICIENT_BUFFER;
while (returnCode == ERROR_INSUFFICIENT_BUFFER)
{
    // Allocate buffer of specified length
    buffer.reset( BYTE[bufferLength] );
    //        
    // Or, in C++14, could use make_unique() instead, e.g.
    //
    // buffer = std::make_unique<BYTE[]>(bufferLength);
    //

    //
    // Call some Win32 API.
    //
    // If the size of the buffer (stored in 'bufferLength') is not big enough,
    // the API will return ERROR_INSUFFICIENT_BUFFER, and the required size
    // in the [in, out] parameter 'bufferLength'.
    // In that case, there will be another try in the next loop iteration
    // (with the allocation of a bigger buffer).
    //
    // Else, we'll exit the while loop body, and there will be either a failure
    // different from ERROR_INSUFFICIENT_BUFFER, or the call will be successful
    // and the required information will be available in the buffer.
    //
    returnCode = ::SomeApiCall(inParam1, inParam2, inParam3, 
                               &bufferLength, // size of output buffer
                               buffer.get(),  // output buffer pointer
                               &outParam1, &outParam2);
}

if (Failed(returnCode))
{
    // Handle failure, or throw exception, etc.
    ...
}

// All right!
// Do some processing with the returned information...
...

Bạn chỉ có thể sử dụng std::vector<char>trong những trường hợp này.
Arthur Tacca

@ArthurTacca - ... nếu bạn không phiền trình biên dịch khởi tạo mọi ký tự trong bộ đệm của bạn thành 0 từng cái một.
TED

9

Tôi đã phải đối mặt với một trường hợp mà tôi phải sử dụng std::unique_ptr<bool[]>, đó là trong thư viện HDF5 (Một thư viện lưu trữ dữ liệu nhị phân hiệu quả, được sử dụng rất nhiều trong khoa học). Một số trình biên dịch (Visual Studio 2015 trong trường hợp của tôi) cung cấp khả năng nénstd::vector<bool> (bằng cách sử dụng 8 bool trong mỗi byte), đây là một thảm họa đối với một cái gì đó như HDF5, không quan tâm đến việc nén đó. Với std::vector<bool>, HDF5 cuối cùng đã đọc rác vì nén đó.

Đoán xem ai đã ở đó để giải cứu, trong trường hợp std::vectorkhông hoạt động và tôi cần phân bổ một mảng động một cách sạch sẽ? :-)


9

Tóm lại: đó là hiệu quả bộ nhớ cao nhất.

A std::stringđi kèm với một con trỏ, độ dài và bộ đệm "tối ưu hóa chuỗi ngắn". Nhưng tình huống của tôi là tôi cần lưu trữ một chuỗi gần như luôn trống, trong một cấu trúc mà tôi có hàng trăm ngàn. Trong C, tôi sẽ chỉ sử dụng char *, và nó sẽ là null hầu hết thời gian. Điều này cũng hoạt động với C ++, ngoại trừ việc a char *không có hàm hủy và không biết tự xóa. Ngược lại, a std::unique_ptr<char[]>sẽ tự xóa khi đi ra khỏi phạm vi. Một khoảng trống std::stringchiếm tới 32 byte, nhưng một khoảng trống std::unique_ptr<char[]>chiếm tới 8 byte, nghĩa là chính xác kích thước của con trỏ.

Nhược điểm lớn nhất là, mỗi khi tôi muốn biết độ dài của chuỗi, tôi phải gọi strlennó.


3

Để trả lời những người nghĩ rằng bạn "phải" sử dụng vectorthay vì unique_ptrtôi có một trường hợp trong lập trình CUDA trên GPU khi bạn phân bổ bộ nhớ trong Thiết bị, bạn phải tìm một mảng con trỏ (có cudaMalloc). Sau đó, khi lấy dữ liệu này trong Máy chủ, bạn phải quay lại một con trỏ và unique_ptrxử lý con trỏ dễ dàng. Chi phí chuyển đổi double*thêm vector<double>là không cần thiết và dẫn đến mất hoàn hảo.


3

Thêm một lý do để cho phép và sử dụng std::unique_ptr<T[]> , chưa được đề cập trong các phản hồi cho đến nay: nó cho phép bạn khai báo loại phần tử mảng.

Điều này rất hữu ích khi bạn muốn giảm thiểu chuỗi #include câu lệnh được trong các tiêu đề (để tối ưu hóa hiệu suất xây dựng.)

Ví dụ -

mygroup.h:

class ALargeAndComplicatedClassWithLotsOfDependencies;

class MyClass {
   ...
private:
   std::unique_ptr<ALargeAndComplicatedClassWithLotsOfDependencies[]> m_InternalArray;
};

mygroup.cpp:

#include "myclass.h"
#include "ALargeAndComplicatedClassWithLotsOfDependencies.h"

// MyClass implementation goes here

Với cấu trúc mã trên, bất kỳ ai cũng có thể #include "myclass.h"và sử dụng MyClassmà không cần phải bao gồm các phụ thuộc triển khai nội bộ được yêu cầu bởi MyClass::m_InternalArray.

m_InternalArrayThay vào đó, nếu được khai báo là a std::array<ALargeAndComplicatedClassWithLotsOfDependencies>, hoặc a std::vector<...>, tương ứng - kết quả sẽ được cố gắng sử dụng loại không hoàn chỉnh, đó là lỗi thời gian biên dịch.


Đối với trường hợp sử dụng cụ thể này, tôi sẽ chọn mẫu Pimpl để phá vỡ sự phụ thuộc - nếu nó chỉ được sử dụng riêng tư, thì định nghĩa có thể được hoãn lại cho đến khi các phương thức lớp được triển khai; nếu nó được sử dụng công khai, thì người dùng của lớp đã có kiến ​​thức cụ thể về nó class ALargeAndComplicatedClassWithLotsOfDependencies. Vì vậy, về mặt logic, bạn không nên chạy vào những tình huống như vậy.

3

Tôi không thể không đồng ý với tinh thần của câu trả lời được chấp nhận đủ mạnh. "Một công cụ cuối cùng"? Cách xa nó!

Theo cách tôi thấy, một trong những tính năng mạnh nhất của C ++ so với C và với một số ngôn ngữ tương tự khác là khả năng diễn đạt các ràng buộc để có thể kiểm tra chúng tại thời điểm biên dịch và có thể ngăn chặn việc lạm dụng ngẫu nhiên. Vì vậy, khi thiết kế một cấu trúc, hãy tự hỏi những gì nó nên cho phép hoạt động. Tất cả các mục đích sử dụng khác đều bị cấm và tốt nhất là nếu các hạn chế đó có thể được triển khai tĩnh (tại thời gian biên dịch) để việc sử dụng sai dẫn đến lỗi biên dịch.

Vì vậy, khi một người cần một mảng, các câu trả lời cho các câu hỏi sau chỉ định hành vi của nó: 1. Kích thước của nó là a) động khi chạy, hoặc b) tĩnh, nhưng chỉ được biết khi chạy, hoặc c) tĩnh và được biết tại thời gian biên dịch? 2. Mảng có thể được phân bổ trên ngăn xếp hay không?

Và dựa trên các câu trả lời, đây là cấu trúc dữ liệu tốt nhất cho một mảng như vậy:

       Dynamic     |   Runtime static   |         Static
Stack std::vector      unique_ptr<T[]>          std::array
Heap  std::vector      unique_ptr<T[]>     unique_ptr<std::array>

Đúng, tôi nghĩ unique_ptr<std::array>cũng nên được xem xét, và cũng không phải là một công cụ của phương sách cuối cùng. Chỉ cần nghĩ những gì phù hợp nhất với thuật toán của bạn.

Tất cả những thứ này tương thích với API C đơn giản thông qua con trỏ thô đến mảng dữ liệu ( vector.data()/ array.data()/ uniquePtr.get()).

PS Ngoài những cân nhắc ở trên, còn có một quyền sở hữu: std::arraystd::vectorcó ngữ nghĩa giá trị (có hỗ trợ riêng để sao chép và chuyển theo giá trị), trong khi unique_ptr<T[]>chỉ có thể được di chuyển (thực thi quyền sở hữu duy nhất). Hoặc là có thể hữu ích trong các kịch bản khác nhau. Ngược lại, mảng tĩnh đơn giản ( int[N]) và mảng động đơn giản ( new int[10]) không cung cấp và do đó nên tránh nếu có thể - điều này có thể xảy ra trong phần lớn các trường hợp. Nếu điều đó là không đủ, các mảng động đơn giản cũng không cung cấp cách nào để truy vấn kích thước của chúng - cơ hội bổ sung cho các lỗi bộ nhớ và lỗ hổng bảo mật.


2

Chúng có thể là câu trả lời đúng nhất có thể khi bạn chỉ chọc một con trỏ thông qua một API hiện có (nghĩ thông báo cửa sổ hoặc tham số gọi lại liên quan đến luồng) có một số đo thời gian sống sau khi bị "bắt" ở phía bên kia của nở, nhưng không liên quan đến mã gọi:

unique_ptr<byte[]> data = get_some_data();

threadpool->post_work([](void* param) { do_a_thing(unique_ptr<byte[]>((byte*)param)); },
                      data.release());

Tất cả chúng ta đều muốn mọi thứ tốt đẹp cho chúng ta. C ++ dành cho những lần khác.


2

unique_ptr<char[]>có thể được sử dụng ở nơi bạn muốn hiệu năng của C và sự tiện lợi của C ++. Hãy xem xét bạn cần phải hoạt động trên hàng triệu (ok, hàng tỷ nếu bạn chưa tin tưởng) chuỗi. Lưu trữ mỗi trong số chúng trong một đối tượng stringhoặc vector<char>đối tượng riêng biệt sẽ là một thảm họa cho các thói quen quản lý bộ nhớ (heap). Đặc biệt nếu bạn cần phân bổ và xóa các chuỗi khác nhau nhiều lần.

Tuy nhiên, bạn có thể phân bổ một bộ đệm duy nhất để lưu trữ nhiều chuỗi đó. Bạn sẽ không thích char* buffer = (char*)malloc(total_size);vì những lý do rõ ràng (nếu không rõ ràng, hãy tìm kiếm "tại sao sử dụng ptrs thông minh"). Bạn muốnunique_ptr<char[]> buffer(new char[total_size]);

Bằng cách tương tự, các cân nhắc về hiệu suất và sự thuận tiện tương tự áp dụng cho phi chardữ liệu (xem xét hàng triệu vectơ / ma trận / đối tượng).


Một không đặt tất cả trong một lớn vector<char>? Câu trả lời, tôi cho rằng, bởi vì chúng sẽ được khởi tạo bằng 0 khi bạn tạo bộ đệm, trong khi chúng sẽ không có nếu bạn sử dụng unique_ptr<char[]>. Nhưng nugget khóa này bị thiếu trong câu trả lời của bạn.
Arthur Tacca

2
  • Bạn cần cấu trúc của mình để chỉ chứa một con trỏ vì lý do tương thích nhị phân.
  • Bạn cần giao diện với API trả về bộ nhớ được phân bổ new[]
  • Công ty hoặc dự án của bạn có một quy tắc chung chống lại việc sử dụng std::vector, ví dụ, để ngăn các lập trình viên bất cẩn vô tình giới thiệu các bản sao
  • Bạn muốn ngăn các lập trình viên bất cẩn vô tình giới thiệu các bản sao trong trường hợp này.

Có một quy tắc chung là các thùng chứa C ++ sẽ được ưu tiên hơn so với việc sử dụng các con trỏ của riêng bạn với các con trỏ. Đó là một quy tắc chung; nó có ngoại lệ Còn nữa; đây chỉ là những ví dụ


0

Nếu bạn cần một mảng động của các đối tượng không thể sao chép được, thì một con trỏ thông minh đến một mảng là cách để đi. Ví dụ, nếu bạn cần một mảng nguyên tử.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.