Thread overview | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 15, 2015 std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
This is a matter with some history behind it. In C, malloc(0) always returns a new, legit pointer that can be subsequently reallocated, freed etc. What most malloc() implementations practically do in their first line is: if (size == 0) size = 1; and take it from there. The reasoning was to make failure of malloc easy to test for. This would suffice: size_t s; ... void* p = malloc(s); if (!p) { ... failed! ... } as opposed to: if (!p && s) { ... failed! ... } That kinda makes sense, but it's not super consistent. For example, realloc() does not obey the same protocol. Calling realloc() with a new size of 0 actually free()s the pointer and then returns null. Anyhow, on to D. In D it's easy to test whether an allocation succeeded: auto buf = alloc.allocate(s); if (buf.length != s) { ... failed! ... } It is a bit subtle, but I think overall it makes everyone's life easier. Thoughts? Andrei |
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 5/15/15 9:36 AM, Andrei Alexandrescu wrote:
> Anyhow, on to D.
To clarify: I want to request all allocators to return null if asked for zero bytes. -- Andrei
|
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Friday, 15 May 2015 at 16:36:29 UTC, Andrei Alexandrescu wrote:
> This is a matter with some history behind it. In C, malloc(0) always returns a new, legit pointer that can be subsequently reallocated, freed etc. What most malloc() implementations practically do in their first line is:
>
> if (size == 0) size = 1;
>
> and take it from there.
>
> The reasoning was to make failure of malloc easy to test for. This would suffice:
>
> size_t s;
> ...
> void* p = malloc(s);
> if (!p) {
> ... failed! ...
> }
>
> as opposed to:
>
> if (!p && s) {
> ... failed! ...
> }
>
> That kinda makes sense, but it's not super consistent. For example, realloc() does not obey the same protocol. Calling realloc() with a new size of 0 actually free()s the pointer and then returns null.
>
> Anyhow, on to D. In D it's easy to test whether an allocation succeeded:
>
> auto buf = alloc.allocate(s);
> if (buf.length != s) {
> ... failed! ...
> }
>
> It is a bit subtle, but I think overall it makes everyone's life easier. Thoughts?
>
>
> Andrei
There is a third option: return a non-null yet invalid pointer (e.g. 0x1) that is used exclusively for empty allocations.
This allows the if(p) pattern and elides the cost of allocating one byte, however it complicates allocator code a bit (resizing, freeing needs to know about this magic pointer), and breaks the contract malloc(size)!=malloc(size).
|
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Friday, 15 May 2015 at 16:36:29 UTC, Andrei Alexandrescu wrote:
> This is a matter with some history behind it. In C, malloc(0) always returns a new, legit pointer that can be subsequently reallocated, freed etc. What most malloc() implementations practically do in their first line is:
>
> if (size == 0) size = 1;
>
> and take it from there.
>
> The reasoning was to make failure of malloc easy to test for. This would suffice:
>
> size_t s;
> ...
> void* p = malloc(s);
> if (!p) {
> ... failed! ...
> }
>
> as opposed to:
>
> if (!p && s) {
> ... failed! ...
> }
>
> That kinda makes sense, but it's not super consistent. For example, realloc() does not obey the same protocol. Calling realloc() with a new size of 0 actually free()s the pointer and then returns null.
>
> Anyhow, on to D. In D it's easy to test whether an allocation succeeded:
>
> auto buf = alloc.allocate(s);
> if (buf.length != s) {
> ... failed! ...
> }
>
> It is a bit subtle, but I think overall it makes everyone's life easier. Thoughts?
Not necessarily a good idea, but there's a third option:
return cast(void*) -1;
Or some other arbitrary non-zero value.
|
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Friday, 15 May 2015 at 16:43:35 UTC, Marc Schütz wrote:
> On Friday, 15 May 2015 at 16:36:29 UTC, Andrei Alexandrescu wrote:
>> This is a matter with some history behind it. In C, malloc(0) always returns a new, legit pointer that can be subsequently reallocated, freed etc. What most malloc() implementations practically do in their first line is:
>>
>> if (size == 0) size = 1;
>>
>> and take it from there.
>>
>> The reasoning was to make failure of malloc easy to test for. This would suffice:
>>
>> size_t s;
>> ...
>> void* p = malloc(s);
>> if (!p) {
>> ... failed! ...
>> }
>>
>> as opposed to:
>>
>> if (!p && s) {
>> ... failed! ...
>> }
>>
>> That kinda makes sense, but it's not super consistent. For example, realloc() does not obey the same protocol. Calling realloc() with a new size of 0 actually free()s the pointer and then returns null.
>>
>> Anyhow, on to D. In D it's easy to test whether an allocation succeeded:
>>
>> auto buf = alloc.allocate(s);
>> if (buf.length != s) {
>> ... failed! ...
>> }
>>
>> It is a bit subtle, but I think overall it makes everyone's life easier. Thoughts?
>
> Not necessarily a good idea, but there's a third option:
>
> return cast(void*) -1;
>
> Or some other arbitrary non-zero value.
Ha! Two fools, one thought :-)
|
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On 5/15/15 9:44 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
> Ha! Two fools, one thought :-)
It's a nice idea but as Vladimir mentioned expand(), reallocate(), free() - all need now to worry about checking two singular values instead of one.
Since there's a long-established tradition that reallocate() and free() accept a null pointer, we can't (and probably shouldn't) change that. So I'm thinking in a way null as a singular value comes for "free".
Andrei
|
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Friday, 15 May 2015 at 17:01:26 UTC, Andrei Alexandrescu wrote:
> On 5/15/15 9:44 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
>> Ha! Two fools, one thought :-)
>
> It's a nice idea but as Vladimir mentioned expand(), reallocate(), free() - all need now to worry about checking two singular values instead of one.
>
> Since there's a long-established tradition that reallocate() and free() accept a null pointer, we can't (and probably shouldn't) change that. So I'm thinking in a way null as a singular value comes for "free".
Yes, and std.allocator is a new piece of software, which means we can choose what makes sense and don't need to worry about compatibility. It just needs to be clearly defined.
|
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Friday, 15 May 2015 at 16:36:29 UTC, Andrei Alexandrescu wrote:
> This is a matter with some history behind it. In C, malloc(0) always returns a new, legit pointer that can be subsequently reallocated, freed etc. What most malloc() implementations practically do in their first line is:
>
> if (size == 0) size = 1;
>
> and take it from there.
>
There are actually 2 way to do this in malloc. Either you return null, but then you need to be able to accept null in the free implementation (as malloc must return a freeable pointer) or you just bump to 1.
Both are valid per spec and there are implementations of malloc for both.
|
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | On 5/15/15 11:37 AM, deadalnix wrote: > On Friday, 15 May 2015 at 16:36:29 UTC, Andrei Alexandrescu wrote: >> This is a matter with some history behind it. In C, malloc(0) always >> returns a new, legit pointer that can be subsequently reallocated, >> freed etc. What most malloc() implementations practically do in their >> first line is: >> >> if (size == 0) size = 1; >> >> and take it from there. >> > > There are actually 2 way to do this in malloc. Either you return null, > but then you need to be able to accept null in the free implementation > (as malloc must return a freeable pointer) or you just bump to 1. > > Both are valid per spec and there are implementations of malloc for both. Ah, nice. I was under the misconception that malloc(0) cannot return null in C. Apparently it's implementation defined at least since C99, see http://stackoverflow.com/a/2132318/348571. Thanks! Andrei |
May 15, 2015 Re: std.allocator.allocate(0) -> return null or std.allocator.allocate(1)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 5/15/15 11:51 AM, Andrei Alexandrescu wrote: > On 5/15/15 11:37 AM, deadalnix wrote: >> On Friday, 15 May 2015 at 16:36:29 UTC, Andrei Alexandrescu wrote: >>> This is a matter with some history behind it. In C, malloc(0) always >>> returns a new, legit pointer that can be subsequently reallocated, >>> freed etc. What most malloc() implementations practically do in their >>> first line is: >>> >>> if (size == 0) size = 1; >>> >>> and take it from there. >>> >> >> There are actually 2 way to do this in malloc. Either you return null, >> but then you need to be able to accept null in the free implementation >> (as malloc must return a freeable pointer) or you just bump to 1. >> >> Both are valid per spec and there are implementations of malloc for both. > > Ah, nice. I was under the misconception that malloc(0) cannot return > null in C. Apparently it's implementation defined at least since C99, > see http://stackoverflow.com/a/2132318/348571. Thanks! Well I added the rule that allocate(0) should return null, there are a few more tests but probably nothing worrisome: https://github.com/andralex/phobos/commit/f73f6ecf1b45b0fc3cffd50d375eb15eb2311220 Andrei |
Copyright © 1999-2021 by the D Language Foundation