C++ Logo

sg16

Advanced search

Re: [SG16] [isocpp-lib-ext] D1030R4 draft 2: std::filesystem::path_view

From: Niall Douglas <s_sourceforge_at_[hidden]>
Date: Fri, 16 Oct 2020 10:12:08 +0100
On 15/10/2020 18:15, Peter Dimov wrote:
> Niall Douglas wrote:
>> >> If we insisted on Allocators, we would force a needless extra
>> dynamic >> memory allocation and memory copy solely because we
>> insisted on >> Allocators.
>> >
>> > I don't see why.
>>
>> My personal primary motivation are functions such as
>> https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-rtlansistringtounicodestring
>>
>> or
>> https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-rtlunicodestringtoansistring
>>
>> which are much more efficient if you let them allocate the destination
>> buffer for you.
>
> OK, I see where you are coming from. However, I'm not quite sure that
> this affects the allocator/deleter question. At the moment, you do this
>
> path_view::c_str<> tmp( path );
>
> to get the default allocation behavior, and you do this
>
> path_view::c_str<char, my_deleter> tmp( path, my_alloc_fn [,
> my_deleter{...}] );
>
> to override it.

Correct.

> In the allocator-based version, you'd do this
>
> path_view::c_str<> tmp( path );
>
> to get the default behavior, and
>
> path_view::c_str<char, my_allocator> tmp( path [, my_alloc] );
>
> to override it>
> There's no reason for the default allocator used in the first case to
> not be able to deallocate (and allocate but that's not going to be
> called) using the NT kernel API.

Mmm. If you replace any notion of "the default allocator" with
"implementation defined allocator", then what you propose would work for me.

However, there is an additional issue: For me personally, Allocators
ought to reserve space AND construct objects within i.e. bit clear the
new allocation. That's inefficient here, because the reencode will
create new objects into the new allocation, so bit clearing is wasted work.

Now, you can simply say that we don't call construct() in the Allocator.
But that seems to me to defeat the spirit of what people mean when they
think of Allocators.

> If you add a memory_resource* overload with nullptr meaning "default",
> the second case can become
>
> path_view::c_str<> tmp( path, my_resource );
>
> at the cost of one additional pointer in c_str<>. Given that
> sizeof(c_str<>) is 1K+, that's probably not going to be an issue.
>
> In fact with the right deduction guides these can turn into
>
> path_view::c_str tmp( path );
>
> path_view::c_str tmp( path, my_alloc_fn, my_deleter );
>
> for R4 and
>
> path_view::c_str tmp( path );
>
> path_view::c_str tmp( path, my_alloc );
>
> path_view::c_str tmp( path, my_resource );
>
> for the hypothetical allocator-taking interface.

I'm not opposed to directly supporting memory_resource& as an extra
overload set. I like memory_resource, because it doesn't force a
dependency on the memory_resource header, whereas bringing in a
dependency on STL allocators drags in the not inconsiderable quantity of
STL allocator machinery. I would really like that anything I add to the
C++ standard library does not drag in a billion tokens of avoidable
dependencies.

A non obvious goal of path views is that they are standalone C++
friendly i.e. allocators may not be available at all. I'll be stating
that in the preamble to draft 3.

Would directly supporting memory_resource& but not STL allocators
directly work for you? Again I do want to emphasise it is trivially easy
for users to wrap up a STL allocator into either the existing mechanism,
or a memory_resource& for that matter.

Niall

Received on 2020-10-16 04:12:13