Comment #0 by dlang-bugzilla — 2018-05-12T01:23:28Z
///////////////////////////// test.d /////////////////////////////
import std.exception : enforce;
import std.experimental.allocator.building_blocks.region;
import std.experimental.allocator.building_blocks.stats_collector;
import std.experimental.allocator.gc_allocator;
import std.typecons : Ternary;
void main()
{
StatsCollector!(Region!GCAllocator, Options.bytesUsed) s;
s.parent = Region!GCAllocator(1024);
auto buf1 = s.allocate(100).enforce();
auto buf2 = s.allocate(100).enforce();
if (s.deallocate(buf1))
{
// OK
return;
}
else
{
// Oops, have to deallocate buf2 first
s.deallocate(buf2).enforce();
s.deallocate(buf1).enforce();
// The region should be empty now, right?
assert(s.empty != Ternary.no); // Nope!
}
}
//////////////////////////////////////////////////////////////////
Comment #1 by dlang-bugzilla — 2018-05-15T23:43:57Z
StatsCollector.deallocate is "Defined whether or not `Allocator.deallocate` is defined". I'm really not sure this was a great idea, because it opens the door to silent memory leaks, and breaks introspection of any allocators that might use this information to switch to a different method of tracking allocations.
There's two ways to fix this:
- Make deallocate always return false (and not count allocations) when ParentAllocator doesn't support deallocation.
- Don't define deallocate if the parent allocator doesn't.
I feel like the first one would defeat the point of always having a deallocate method. Still, the way things are now is obviously broken.
Andrei, any thoughts?
Comment #2 by robert.schadek — 2024-12-01T16:33:44Z