Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I clone an object by copying its memory?

I need to have undo+redo stack for a limited number of classes under my control that has to be very very very fast and using RTTI and XML or streams is not feasible as the count of instances can be as high as 2000+ in nested object lists. The objects need to be copied into and out of via memento pattern and reloaded instantly.

Is there a way to clone objects by copying the memory and re-instantiating the objects from that memory?

like image 580
MX4399 Avatar asked Oct 17 '11 18:10

MX4399


People also ask

Can an object be copied?

There are several ways to copy an object, most commonly by a copy constructor or cloning. Copying is done mostly so the copy can be modified or moved, or the current value preserved. If either of these is unneeded, a reference to the original data is sufficient and more efficient, as no copying occurs.

How do you clone an object in darts?

Map clonedObject = JSON. decode(JSON. encode(object)); If you're using a custom class as a value in the object to clone, the class either needs to implement a toJson() method or you have to provide a toEncodable function for the JSON.


4 Answers

Hardly. You can easily copy the memory of an object, but part of that memory will be pointers in which case you only copy the reference. Those pointers can include strings and other objects as well.

I think the best way is to inherit these classes from TPersistent (or any decendant) en implement the Assign method for each of them. That way, you can create a second instance and assign the object to that new instance. In the Assign implementation you can decide for yourself what data should be copied and what not.

like image 68
GolezTrol Avatar answered Oct 01 '22 22:10

GolezTrol


2000+ nested objects is not so huge, and won't be so slow, even with RTTI (disk access or compression will be much slower). With a direct SaveToStream manual serialization, it is very fast, if you use FastMM4 (the default memory manager since Delphi 2006).

Perhaps you may change your algorithm and use dynamic arrays instead (there is an open source serializer here). But your data may not fit this kind of records.

Or never/seldom release memory, and only use objects or record references. You can have an in-memory pool of objects, with some kind of manual garbage collector, and only handle reference to objects (or records).

If you have string inside the objects, you may not reallocate them and maintain a global list of used strings: reference counting and copy-on-write will make it much faster than standard serialization and allocation (even with FastMM4).

In all cases, it is worth making a real profiling of your application. General human guess about performance bottlenecks are most of the time wrong. Only trust a profiler, and a wall clock. Perhaps your current implementation is not so slow, and the real bottleneck is not the object process, but somewhere else.

Do not optimize too early. "Make it right before you make it fast. Make it clear before you make it faster. Keep it right when you make it faster." — Kernighan and Plauger, Elements of Programming Style.

like image 26
Arnaud Bouchez Avatar answered Oct 01 '22 22:10

Arnaud Bouchez


A simple way to clone an object is :

  • Derive your clonable class from TPersistent
  • Implement the Assign procedure

See Memento design pattern example here : http://sourcemaking.com/design_patterns/memento/delphi/1

like image 36
TridenT Avatar answered Oct 01 '22 20:10

TridenT


An approach I have used for this situation in the past is to declare a record with the part of the object I need to retain, and use that record within a class. See my old answer at Optimizing Class Size in Delphi. Is there something like "packed classes"? for an example.

As records are copied on assignment, it is then easy to copy the fields from one object type to another.

e.g.

TMyFields = record
  ID: Integer;
  Name: string;
end;

TMyClass = class(TPersistent)    
 private
  FFields: TMyFields;
  FStack: TStack;
  class TStackItem = class(TObject)
  public
    Fields: TMyFields;
  end;

protected
   property ID: integer read FFields.ID;
   property Name: string read FFields.Name;
   procedure Push;
   // etc...
end;


procedure TMyClass.Push;
var
  NewItem: TStackItem;
begin
  NewItem := TStackItem.Create;
  NewItem.Fields := FFields;
  FStack.Push(NewItem);
end;

Of course, as you are using XE, you could use Generics.Collections.TObjectStack instead.

like image 25
Gerry Coll Avatar answered Oct 01 '22 20:10

Gerry Coll