www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - New D technique - disable usage of "new" and "delete"

reply Basile B. <b2.temp gmx.com> writes:
I was chatting on IRC. One of the topic was about a " nogc" 
thread. I suggested something like "core.thread.NoGcThread" that 
would take a " nogc" function but then i realized that this 
hypothetical class could still be allocated on the GC heap.
So "new" and "delete" would have to be disabled...Despite of 
being deprecated it appears that class allocators and 
deallocators can be used for that purpose, without compiler 
changes:

---
class Foo
{
      disable new (size_t size){return null;}
      disable delete (void* p){}
}

void main()
{
     static assert(!__traits(compiles, new Foo));
     import std.experimental.allocator;
     import std.experimental.allocator.mallocator;

     auto f = make!Foo(Mallocator.instance);
     dispose(Mallocator.instance, f);

     // auto g = new Foo, // doesn't work
}
---

What's the point ?

- It's fun to discover that.
- Libraries that don't want their aggregates to reside on the GC 
heap can use this, with a mixin. (note: although the GCAllocator 
can still be used...)
Jan 05
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 5 January 2018 at 19:44:38 UTC, Basile B. wrote:
 [snip]
 - Libraries that don't want their aggregates to reside on the 
 GC heap can use this, with a mixin. (note: although the 
 GCAllocator can still be used...)
Cool. Not sure I'm following with your point with the mixin. A mixin like below works fine, but it would be a little annoying to get the constructors working. The only way I can think of is to pass them as strings to the create function. import std.experimental.allocator; import std.experimental.allocator.mallocator; class Foo { int a; disable new (size_t size){return null;} disable delete (void* p){} } string create(T, string name)() { import std.conv : to; return T.stringof ~ " " ~ name ~ " = make!" ~ T.stringof ~ "(Mallocator.instance);\n" ~ "scope(exit) dispose(Mallocator.instance, " ~ name ~ ");"; } void main() { mixin(create!(Foo, "f")); f.a = 1; }
Jan 05
parent reply Basile B. <b2.temp gmx.com> writes:
On Friday, 5 January 2018 at 20:45:20 UTC, jmh530 wrote:
 On Friday, 5 January 2018 at 19:44:38 UTC, Basile B. wrote:
 [snip]
 - Libraries that don't want their aggregates to reside on the 
 GC heap can use this, with a mixin. (note: although the 
 GCAllocator can still be used...)
Cool. Not sure I'm following with your point with the mixin. A mixin like below works fine, but it would be a little annoying to get the constructors working. The only way I can think of is to pass them as strings to the create function. import std.experimental.allocator; import std.experimental.allocator.mallocator; class Foo { int a; disable new (size_t size){return null;} disable delete (void* p){} } string create(T, string name)() { import std.conv : to; return T.stringof ~ " " ~ name ~ " = make!" ~ T.stringof ~ "(Mallocator.instance);\n" ~ "scope(exit) dispose(Mallocator.instance, " ~ name ~ ");"; } void main() { mixin(create!(Foo, "f")); f.a = 1; }
Yeah, i didn't explain correctly the mixin thing. The mixin would be used to disable "new" and "delete", e.g enum disableNewAndDelete = " disable new (size_t size){return null;} disable delete (void* p){}"; and then you mix it in the classes of the framework that doesn't want "new" and "delete" to be used: mixin(disableNewAndDelete);
Jan 05
parent jmh530 <john.michael.hall gmail.com> writes:
On Friday, 5 January 2018 at 20:51:14 UTC, Basile B. wrote:
 Yeah, i didn't explain correctly the mixin thing.
 The mixin would be used to disable "new" and "delete", e.g

     enum disableNewAndDelete = " disable new (size_t 
 size){return null;}  disable delete (void* p){}";

 and then you mix it in the classes of the framework that 
 doesn't want "new" and "delete" to be used:

     mixin(disableNewAndDelete);
It occurs to me that you can use this to disable unsafe features (pointer arithmetic, casting immutability and shared most notably). For instance, something like below as a rough sketch (I didn't check that it compiles) struct Safe(T) { import std.traits : isPointer, Unqual; T _data; alias _data this; disable this(); this(T x) { _data = x; } property T data() { return _data; } property void data(T x) { _data = x; } static if (isPointer!T) { disable U opCast(U)() if (isPointer!U && U != void*) disable T opBinary(string op)(T rhs) disable T opUnary(string op)() //also disable opIndex, opDollar, opIndexUnary, opIndexAssign, ... //opIndexOpAssign } static if (isMutable!T) { disable immutable(T) opCast(immutable(T))() } else { disable Unqual!T opCast(Unqual!T)() } //add disable for shared }
Jan 07