Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gsl::dyn_array<T, Deleter>? #1169

Open
cgettys-microsoft opened this issue Nov 13, 2024 · 1 comment
Open

gsl::dyn_array<T, Deleter>? #1169

cgettys-microsoft opened this issue Nov 13, 2024 · 1 comment
Assignees

Comments

@cgettys-microsoft
Copy link

Good day folks,

I'm a Microsoft employee working on one of our large internal codebases (happy to discuss more offline :)).  CppCoreGuidelines proposes that there should be a gsl::dyn_array type:

dyn_array // ??? needed ??? A heap-allocated array. The number of elements is determined at construction and fixed thereafter. The elements are mutable unless T is a const type. Basically a span that allocates and owns its elements.
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslowner-ownership-pointers

We've been beginning to embrace span<T> and unique_ptr<T, OurCustomDeleter>. However, we've noticed that there's a missing type for migrating existing code.
Namely, we have:

  • unique_ptr<T> for owned single elements,
  • unique_ptr<T[]> for owned arrays where we need not track the length
  • vector<T> (and some custom equivalents) for owned, resizeable arrays
  • ```span`` for borrowed/unowned arrays with length tracked
  • And a gap (which appears that dyn_array<T> would fill if it existed) for owned, non-resizable arrays.

For us, our operator delete is global (and thus the corresponding deleter is compressible). However, our operator new is stateful / it requires a pointer to the allocator to use (because we do arena allocation and the like).

So, the gap dyn_array<T, Deleter> could fill is instead filled with:

  • Separate unique_ptr<T[]> and length arguments (e.g. inout arguments instead of returning a class using NVRO) - clunky and easy to make mistakes
  • Separate T* and length - even worse than the previou soption.
  • vector<T> can't fill the gap either - instead of sizeof(size_t) +sizeof(T*) (call it 16 bytes on 64 bit arches), vector<T> imposes an additional sizeof(T*) due to the length and capacity split, and usually at least another sizeof(T*) for the custom allocator.
    A dyn_array<T, Deleter> thus would be very useful to us, as it has no additional stack overhead (ignoring structure vs primitive type argument passing differences in e.g. msvc's ABI, which are unfortunate but probably livable). In other words, it would be a drop-in replacement with the same semantics as having a unique_ptr<T[], Deleter>, but safer.

While our use case is somewhat niche, I suspect we're not the only codebase internally or externally who would find this useful, so I thought I should file an issue and ask if there are plans to add it.

Related issues:
isocpp/CppCoreGuidelines#1633
#348
#505
#890

@carsonRadtke
Copy link
Collaborator

Thank you for providing a detailed description of the issues you are facing and what you would like to see out of a solution. It is very helpful. As per the linked CppCoreGuidelines issue, we are finalizing a proposal to guide the implementation of a gsl::dyn_array and will be passing it on for feedback in the coming weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants