2009-04-23 23 views
14
int main(void) 
{ 
    std::string foo("foo"); 
} 

Hiểu biết của tôi là mã ở trên sử dụng trình phân bổ mặc định để gọi mới. Vì vậy, mặc dù std :: string foo được cấp phát trên stack, bộ đệm bên trong của foo được cấp phát trên heap.Làm cách nào để phân bổ chuỗi std :: trên ngăn xếp bằng cách sử dụng chuỗi triển khai của glibc?

Làm cách nào để tạo chuỗi được phân bổ hoàn toàn trên ngăn xếp?

+0

Hãy để tôi sửa đổi điều đó thành "làm cách nào tôi có thể tạo std :: basic_string được phân bổ hoàn toàn trên ngăn xếp?" – poindexter

+0

Chỉ cần liên kết đến một câu hỏi tương tự: http://stackoverflow.com/questions/354442/looking-for-c-stl-like-vector-class-but-using-stack-storage –

Trả lời

19

tôi muốn làm chỉ này bản thân mình thời gian gần đây và thấy đoạn mã sau chiếu sáng:

Chronium's stack_container.h

Nó định nghĩa một mới std::allocator có thể cung cấp phân bổ dựa trên stack cho việc phân bổ ban đầu lưu trữ cho STL container. Tôi tìm ra cách khác để giải quyết vấn đề cụ thể của mình, vì vậy tôi đã không thực sự sử dụng mã đó, nhưng có lẽ nó sẽ hữu ích cho bạn. Hãy chắc chắn để đọc các ý kiến ​​trong các mã liên quan đến cách sử dụng và báo trước.

Đối với những ai đã đặt câu hỏi về tiện ích và sự tỉnh táo để làm điều này, hãy xem xét:

  • Thông thường bạn biết một tiên nghiệm rằng chuỗi của bạn có kích thước tối đa hợp lý. Ví dụ: nếu chuỗi sẽ lưu trữ một số nguyên 32 bit được định dạng thập phân, bạn biết rằng bạn không cần nhiều hơn 11 ký tự để làm như vậy. Không cần một chuỗi có thể phát triển động đến kích thước không giới hạn trong trường hợp đó.
  • Phân bổ từ ngăn xếp nhanh hơn trong nhiều trường hợp so với phân bổ từ vùng heap.
  • Nếu chuỗi được tạo và hủy thường xuyên (giả sử nó là một biến cục bộ trong một hàm tiện ích thường được sử dụng), phân bổ từ ngăn xếp thay vì vùng heap sẽ tránh sự phân mảnh trong phân bổ heap. Đối với các ứng dụng sử dụng nhiều bộ nhớ, điều này có thể là một sự thay đổi trò chơi.

Một số người đã nhận xét rằng chuỗi sử dụng phân bổ dựa trên ngăn xếp sẽ không phải là std::string như thể bằng cách nào đó làm giảm tiện ích của nó. Đúng, bạn không thể sử dụng hai thay thế cho nhau, vì vậy bạn sẽ không thể chuyển số stackstring của mình cho các chức năng mong đợi một số std::string. Nhưng (nếu bạn làm đúng), bạn sẽ có thể sử dụng tất cả các chức năng thành viên giống nhau trên stackstring mà bạn sử dụng ngay bây giờ trên std::string, như find_first_of(), append(), v.v. begin()end() vẫn hoạt động tốt, vì vậy bạn sẽ có thể sử dụng nhiều thuật toán STL. Chắc chắn, nó sẽ không được std::string theo nghĩa hẹp nhất, nhưng nó vẫn sẽ là một "chuỗi" theo nghĩa thực tế, và nó vẫn sẽ khá hữu ích.

+0

Cảm ơn con trỏ tới một số mã thú vị. –

+1

Bạn có thể sử dụng nhiều thuật toán STL trên một mảng trống của char trên stack, nhưng ai đó đã đề xuất và bỏ phiếu xuống. Người hỏi sẽ phải quyết định các tính năng của std :: string anh ta cần ... –

+2

Điều này không làm việc cho std :: basic_string của glibc, nó gọi hàm tạo mặc định của Allocator, mà StackAllocator không hỗ trợ. – poindexter

0

Tôi nghi ngờ rằng làm một điều như vậy sẽ khó làm, tôi tự hỏi tại sao bạn muốn làm điều đó? Để phân bổ một cái gì đó hoàn toàn trên stack, trình biên dịch cần phải biết tại thời gian biên dịch kích thước chính xác của nó là gì - trong ví dụ của bạn, nó sẽ cần biết không chỉ kích thước của siêu dữ liệu std::string mà còn cả kích thước của dữ liệu chuỗi chinh no. Đây không phải là quá linh hoạt, bạn có thể sẽ cần các loại chuỗi khác nhau tùy thuộc vào kích thước của dữ liệu chuỗi bạn muốn bao gồm trong nó - không phải là nó sẽ không thể làm, chỉ cần nó sẽ có xu hướng phức tạp những thứ lên một chút.

+1

"có thể bạn sẽ cần chuỗi khác nhau loại tùy thuộc vào kích thước của dữ liệu chuỗi bạn muốn bao gồm trong đó ". Chào mừng bạn đến với Symbian! –

-3
  • std :: chuỗi sẽ luôn quản lý bộ nhớ trong của nó bằng mới/xóa.
  • Không chắc chắn tại sao câu hỏi của bạn chứa thực hiện chuỗi của glibc. Việc triển khai chuỗi thư viện chuẩn C++ không liên quan gì đến glibc.
  • Cách duy nhất để lưu trữ chuỗi trên ngăn xếp là sử dụng mảng C char trên ngăn xếp (giống như những gì Shhnap đã nêu). Nhưng đó có thể không phải là điều bạn muốn dù sao :-)
+0

Có thực sự là một cái gì đó trong tiêu chuẩn liên quan đến điểm đầu tiên .. AFAIK, việc thực hiện nội bộ là miễn phí để làm tối ưu hóa kích thước chuỗi nhỏ và không liên quan đến đống. –

+2

Majkara là chính xác, các chuỗi nhỏ (<16 ký tự trong việc triển khai MSVC) thường được cấp phát trên ngăn xếp và không liên quan đến việc cấp phát bộ nhớ heap. – newgre

+0

std :: string định nghĩa giao diện không thực hiện. Tôi đặc biệt hỏi về việc thực hiện glibc vì đó là những gì tôi đang làm việc. Nếu tôi đang sử dụng triển khai MSVC, tôi sẽ không hỏi câu hỏi này. May mắn thay tôi đã được cung cấp một câu trả lời được thực hiện độc lập. – poindexter

11

Vấn đề là std::basic_string có thông số mẫu cho người cấp phát. Nhưng std::string không phải là mẫu và không có tham số. Vì vậy, về nguyên tắc, bạn có thể sử dụng một sự khởi tạo của std::basic_string với một người cấp phát sử dụng bộ nhớ trên ngăn xếp, nhưng nó sẽ không là std::string. Đặc biệt, bạn sẽ không nhận được đa hình thời gian chạy và bạn không thể chuyển các đối tượng kết quả vào các hàm mong đợi một std::string.

+1

Tôi không chắc nó sẽ hoạt động như thế nào? Chính xác làm thế nào để bạn đề xuất để có các cấp phát sửa đổi khung stack của người gọi của nó?Đơn giản chỉ cần làm một alloca() trong allocator sẽ không hoạt động vì bộ nhớ đó sẽ được tự động giải phóng khi allocator trả về con trỏ, hoặc khi std :: string's constructor trả về nếu phân bổ được inlined. –

+0

Đánh tôi với nó :-) –

+1

Bạn hoàn toàn đúng, người cấp phát chỉ có thể làm việc vì anh ta không nói * nơi * trên dữ liệu ngăn xếp mà anh ta muốn chuỗi đó. Người cấp phát sẽ cần quyền truy cập vào một khối ngăn xếp thông qua dữ liệu cá thể. Một chút giống như các thư viện chuỗi an toàn của DJB (C, không phải C++), sử dụng một khối giới hạn không gian ngăn xếp bởi vì đó là một cách rẻ tiền và dễ dàng để hạn chế sử dụng bộ nhớ cho mỗi chủ đề –

4

Bạn không thể. Trừ ...

std::string là một instantiation của

std::basic_string<class CharType, 
        class Traits=char_traits<CharType>, 
        class Allocator=allocator<CharType> > 

Bạn hình dung có thể định nghĩa một lớp cấp phát sử dụng alloca cho quản lý bộ nhớ. Điều này sẽ chỉ hoạt động nếu chính Allocator và các phương thức basic_string gọi trực tiếp hoặc gián tiếp, tất cả đều là inline. Đối tượng basic_string được tạo với trình phân bổ này sẽ không một std::string, nhưng nó sẽ hoạt động (chủ yếu) như nó. Tuy nhiên, đây sẽ là một số lượng công bằng cho công việc vì lợi ích hạn chế. Cụ thể, việc sử dụng lớp này để trả về các giá trị từ một hàm sẽ là một động thái hạn chế nghề nghiệp.

Tôi không có ý tưởng lý do tại sao bạn hoặc bất kỳ ai khác muốn thực hiện việc này.

+2

+1, modulo bình luận cho câu trả lời của tôi, rằng alloca không thực sự làm điều đó bởi vì std :: basic_string gọi xuống vào allocator, do đó, nó "quá muộn" bởi sau đó sử dụng alloca. Không thể nhớ làm thế nào alloca tương tác với inlining mặc dù - có thể với số tiền tàn bạo nó chỉ có thể xảy ra để làm việc cho một thực hiện STL cụ thể và cài đặt trình biên dịch? –

+0

Trình biên dịch sẽ cần phải đi con đường ra khỏi con đường của nó để cung cấp cho các phương pháp nội tuyến khung stack của riêng mình. OTOH, đặt cược vào đó là * một hành động hạn chế nghề nghiệp khác. –

+1

alloca không phải là POSIX, vì vậy tôi thậm chí sẽ không xem xét nó. Đối với lý do tại sao một người nào đó muốn làm điều này, tôi chỉ cho bạn câu trả lời của Eric Melski. – poindexter

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