www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Reuse object memory?

reply "Namespace" <rswhite4 gmail.com> writes:
Is it somehow possible to reuse the memory of an object?

My current idea is:
----
 nogc
T emplace(T, Args...)(ref T obj, auto ref Args args) nothrow if 
(is(T == class)) {
     if (obj is null)
         return null;

     enum size_t SIZE = __traits(classInstanceSize, T);

     void[] buf = (cast(void*) obj)[0 .. SIZE];
     buf = typeid(T).init[];
     //obj = cast(T) buf.ptr;

     static if (args.length)
         obj.__ctor(args);

     return obj;
}

Foo f = new Foo(42);
Foo f2 = emplace(f, 23);
----

But is there a more elegant way to do that? Maybe without calling 
the internal __ctor?

In C++ you can do that:

----
#include <iostream>

class Foo {
public:
	int id;
	
	explicit Foo(int _id) : id(_id) { }
};

int main() {
	Foo* f = new Foo(42);
	std::cout << f << ':' << f->id << std::endl;
	new (f) Foo(23);
	std::cout << f << ':' << f->id << std::endl;
	delete f;
}
----
Apr 19 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/19/2015 09:04 AM, Namespace wrote:

 Is it somehow possible to reuse the memory of an object?
Yes, when you cast a class variable to void*, you get the address of the object.
  nogc
 T emplace(T, Args...)(ref T obj, auto ref Args args) nothrow if (is(T ==
 class)) {
There is already std.conv.emplace: import std.conv; import core.memory; class Foo { int i; this(int i) { this.i = i; } } void main() { void* buffer = GC.calloc(1234); enum FooSize = __traits(classInstanceSize, Foo); /* These two object are constructed on a void[] slice: */ auto f = emplace!Foo(buffer[0..FooSize], 42); auto f2 = emplace!Foo(buffer[0..FooSize], 43); /* f3 is constructed on top of an existing object: */ auto f2_addr = cast(void*)f2; auto f3 = emplace!Foo(f2_addr[0..FooSize], 44); /* At this point, all three reference the same object: */ assert(&f.i == &f2.i); assert(&f.i == &f3.i); } Ali
Apr 19 2015
next sibling parent reply "Namespace" <rswhite4 gmail.com> writes:
And if I have an already instantiated object?
----
Foo f = new Foo();
// reuse f's memory
----
Is there an nicer way to override the memory instead of:
----
void[] buf = (cast(void*) f)[0 .. __traits(classInstanceSize, 
Foo)];
buf = typeid(Foo).init[]; // or: buf = f.classinfo.init[];
----
?

The void* cast looks very ugly.
Apr 19 2015
parent "Namespace" <rswhite4 gmail.com> writes:
It seems that D has currently no direct support to reuse object 
memory.
D should add a new-placement syntax:
----
Foo f = new Foo(42);
new (f) Foo(23);
----
and/or should add an emplace overload which takes an object:
----
T emplace(T, Args...)(ref T obj, auto ref Args args) if (is(T == 
class)) {
     if (obj is null)
         return null;

     enum size_t ClassSize = __traits(classInstanceSize, T);
     void[] buf = (cast(void*) obj)[0 .. ClassSize];

     import std.conv : emplace;
     return emplace!(T)(buf, args);
}
----
Apr 19 2015
prev sibling parent reply "Namespace" <rswhite4 gmail.com> writes:
On Sunday, 19 April 2015 at 21:17:18 UTC, Ali Çehreli wrote:
 On 04/19/2015 09:04 AM, Namespace wrote:

 Is it somehow possible to reuse the memory of an object?
Yes, when you cast a class variable to void*, you get the address of the object.
  nogc
 T emplace(T, Args...)(ref T obj, auto ref Args args) nothrow
if (is(T ==
 class)) {
There is already std.conv.emplace: import std.conv; import core.memory; class Foo { int i; this(int i) { this.i = i; } } void main() { void* buffer = GC.calloc(1234); enum FooSize = __traits(classInstanceSize, Foo); /* These two object are constructed on a void[] slice: */ auto f = emplace!Foo(buffer[0..FooSize], 42); auto f2 = emplace!Foo(buffer[0..FooSize], 43); /* f3 is constructed on top of an existing object: */ auto f2_addr = cast(void*)f2; auto f3 = emplace!Foo(f2_addr[0..FooSize], 44); /* At this point, all three reference the same object: */ assert(&f.i == &f2.i); assert(&f.i == &f3.i); } Ali
I'm sorry if I annoy you, but I would really like to know how you would reuse already instantiated storage of an existing object. Example code: ---- final class Foo { uint id; nogc this(uint id) { this.id = id; } } Foo f = new Foo(42); ----
Apr 20 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/20/2015 12:05 PM, Namespace wrote:

 I'm sorry if I annoy you
Not at all! :) Sorry for not responding earlier.
, but I would really like to know how you would
 reuse already instantiated storage of an existing object.

 Example code:
 ----
 final class Foo {
      uint id;

       nogc
      this(uint id) {
          this.id = id;
      }
 }

 Foo f = new Foo(42);
 ----
Something like the following works. I chose to set the old object to null but it is not necessary: final class Foo { uint id; nogc this(uint id) { this.id = id; } } C reuse(C, T...)(ref C old, T ctorParams) { import std.conv; import std.typetuple; enum objectSize = __traits(classInstanceSize, C); void* oldPlace = cast(void*)old; C newObject = emplace!C(oldPlace[0..objectSize], ctorParams); old = null; return newObject; } void main() { Foo f = new Foo(42); auto f2 = f.reuse(43); assert(f is null); assert(f2.id == 43); } Ali
Apr 20 2015
next sibling parent reply "Namespace" <rswhite4 gmail.com> writes:
Thank you. Do you mean this is worth a PR, to add this 
functionality to Phobos?
My current code looks like this: 
http://dpaste.dzfl.pl/19b78a600b6c
Apr 20 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/20/2015 02:44 PM, Namespace wrote:

 Thank you. Do you mean this is worth a PR, to add this
 functionality to Phobos?
I am not familiar with such a need so I don't have a strong opinion. However, if an object needs to be emplaced on top of an existing one, I can imagine that the original object was emplaced on some piece of memory anyway. In that case, the problem becomes "emplacing an object on a piece of memory", which is already supported by std.conv.emplace. Your idea seems to be for the case where the original object is created by some third party code, and that they want us to replace it with another object. If they are aware of the wholesale change in the object, fine. :) Ali
Apr 20 2015
parent "Namespace" <rswhite4 gmail.com> writes:
On Monday, 20 April 2015 at 21:58:59 UTC, Ali Çehreli wrote:
 On 04/20/2015 02:44 PM, Namespace wrote:

 Thank you. Do you mean this is worth a PR, to add this
 functionality to Phobos?
I am not familiar with such a need so I don't have a strong opinion. However, if an object needs to be emplaced on top of an existing one, I can imagine that the original object was emplaced on some piece of memory anyway. In that case, the problem becomes "emplacing an object on a piece of memory", which is already supported by std.conv.emplace. Your idea seems to be for the case where the original object is created by some third party code, and that they want us to replace it with another object. If they are aware of the wholesale change in the object, fine. :) Ali
I have currently an array of objects which may be reloaded (it's a tilemap). If the array is reused, I can do that with: ---- arr.length = 0; arr.assumeSafeAppend(); ---- But then I thought: why not reuse the memory of the objects? In C++ you can do that very elegant, but in D I have to produce garbage since the old object stays alive until the GC collects it and I have to allocate new GC memory.
Apr 20 2015
prev sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Monday, 20 April 2015 at 21:36:35 UTC, Ali Çehreli wrote:
 final class Foo {
     uint id;

      nogc
     this(uint id) {
         this.id = id;
     }
 }

 C reuse(C, T...)(ref C old, T ctorParams)
 {
     import std.conv;
     import std.typetuple;

     enum objectSize = __traits(classInstanceSize, C);

     void* oldPlace = cast(void*)old;
It's probably better to call the destructor here before calling emplace, to complete the lifecycle of the old object.
     C newObject = emplace!C(oldPlace[0..objectSize], 
 ctorParams);

     old = null;

     return newObject;
 }

 void main()
 {
     Foo f = new Foo(42);

     auto f2 = f.reuse(43);

     assert(f is null);
     assert(f2.id == 43);
 }

 Ali
Apr 21 2015