C/C++ C++ : Deep Copying of an Object

  • Thread starter Thread starter Hepth
  • Start date Start date
  • Tags Tags
    C++
Click For Summary
Creating a deep copy of a neural network structure in C++ requires careful management of memory and object ownership. The discussion emphasizes the need for each class—Network, Layer, Neuron, and Connection—to implement a copy constructor, assignment operator, and destructor, adhering to the "Rule of Three." However, using standard library containers like std::vector can simplify this process significantly. Vectors automatically handle deep copying, eliminating the need for manual copying of each pointer or array. This approach allows for easier management of object lifetimes and reduces the complexity of the code. The conversation also touches on the potential benefits of implementing serialization for class data, which can facilitate saving and restoring the state of the neural network. The consensus is that transitioning from raw pointers to vectors is a more efficient and less error-prone strategy for achieving the desired deep copy functionality.
Hepth
Science Advisor
Gold Member
Messages
457
Reaction score
40
I'm making a basic neural network, and I haven't programmed in an object oriented way since java in undergraduate. Everything lately has been c and fortran 77.

I have an object that is a "Network"
In addition to functions and locals, it includes a pointer to an array of another object "Layer"
Each Layer includes a pointer to an array of "Neuron"
Each Neuron includes a pointer to an array of "Connection"
Connection just has a double "val".

How do I create an operator and copy constructor such that when I have

Code:
Network A;
A.Randomize(); //Sets everything to random values at the Connection level
Network B = A; //Here I want to define a copy
B.Randomize(); //Randomize B

And then
A.Layers[0].Neurons[0].Connections[0].val
B.Layers[0].Neurons[0].Connections[0].val

should be different. As it stands, the basic shallow copy makes copies of the pointer locations, rather than the deep values contained. So A.Layer and B.Layer point to the same location, so any changes to B makes changes to A. I want to make a NEW duplicate, that does a deep copy.

Do I need to go to each class and add a more deep copy constructor with rules for EVERY pointer/array/object in that class, and how to copy itself deeply?

It feels like a lot of work, where if inside say Neuron class I have a bunch of different pointers, I would have to make the copy constructor copy the value of each one?

Sorry if its not clear, I have an idea of what I'm doing but I'm having trouble getting it done. It also doesn't help that I am working off of someone elses template to a very basic degree.
 
Technology news on Phys.org
Hepth said:
Do I need to go to each class and add a more deep copy constructor with rules for EVERY pointer/array/object in that class, and how to copy itself deeply?

Pretty much so, yes. In fact, each class should have a destructor, a (deep) copy constructor, and an assignment operator (the "Rule of Three").

This would be easier if the classes used vectors instead of arrays. You can copy a vector of objects (e.g in an assignment statement), and it automatically copies all the objects it contains, according to their constructors. With arrays, you have to copy each object yourself. ?:)
 
  • Like
Likes D H
jtbell said:
This would be easier if the classes used vectors instead of arrays.
What jtbell said!

Hepth said:
I have an object that is a "Network"
In addition to functions and locals, it includes a pointer to an array of another object "Layer"
Each Layer includes a pointer to an array of "Neuron"
Each Neuron includes a pointer to an array of "Connection"
Connection just has a double "val".
If you follow jtbell's advice, you don't need to write a copy constructor, assignment operator, or destructor. The C++ standard library contains some very powerful capabilities, they optimize very nicely, and they oftentimes eliminate the need to write those rule of three (C++11: rule of five) special member functions.

Code:
class Connection {
public:
   // Default constructor
   Connection(double v=0.0) : val(v) {}

   // Other member functions
...

   double val;
};

There is need to declare a copy constructor, assignment operator, destructor for class Connection. In fact, you don't want to. The implicitly-defined functions do exactly what the doctor ordered. If you're of the pedantic sort, you can inform the reader of your code that you are explicitly using those implicitly declared and defined member functions:

Code:
class Connection {
public:
   // Default constructor
   Connection(double v=0.0) : val(v) {}

  // Copy constructor, assignment operator, and destructor
  Connection(const Connection&) = default;
  Connection& operator=(const Connection&) = default;
  ~Connection() = default;

   // And in the case of C++11/14 ...
  Connection(Connection&&) = default;
  Connection& operator=(Connection&&) = default;
   // Other member functions
...

   double val;
};

I kind of like that myself. It's not too that extra typing, and it tells me as a reader of the code that the author of the class has explicitly thought about whether it makes sense to get those freebies.

What about higher levels? Here's neuron, which now uses a vector rather than a primitive array:

Code:
class Neuron {
public:
   // Default constructor, needed if you define a non-default constructor
   // and if you want a default constructor. I'm assuming C++11 here.
   Neuron() = default;

   // Defaulted special member functions.
   // Once again I'm being pedantic here. Now this is perhaps too much typing.
  Neuron(const Neuron&) = default;
  Neuron(Neuron&&) = default;
  Neuron& operator=(const Neuron&) = default;
  Neuron& operator=(Neuron&&) = default;
  ~Neuron() = default;
   ...
   std::vector<Connection> connections;
};

And similarly for classes Layer and Network.

The rule of three is a pain in the rear. The rule of five, and even bigger pain. The easiest way around this is to use Peter Sommerlad's "rule of zero": Write your classes so you don't need to define any of the special member functions that are subject to the rule of three / rule of five. Use standard library containers or smart points.
 
DH, I'm going to implement it that way, but basically it becomes that YOUR copy is a shallow copy, but since I am using vectors rather than pointers to arrays, its easy and I can just use the normal shallow copy for everything. Right?

It doesn't solve the problem of if I had a pointer for some reason deep in my tree that the copy used would just copy the address rather than the value?
 
Hepth said:
DH, I'm going to implement it that way, but basically it becomes that YOUR copy is a shallow copy, but since I am using vectors rather than pointers to arrays, its easy and I can just use the normal shallow copy for everything. Right?
It's a deep copy rather than a shallow copy if you replace all those primitive arrays with std::vectors.

Make a Neuron contain a vector of Connection objects, a Layer contain a vector of Neuron objects, a Network contain a vector of Layer objects. The implicitly defined copy constructor for Network invokes the std::vector copy constructor to make a copy of the source Network object's connections vector. The std::vector copy constructor makes an element-by-element copy. That means the Lay objects will be copied element by element, which in turn means the Neuron elements within each Layer will be copied element by element, which in turn means the Connection objects within each Neuron will copied element by element. That's a deep copy, just what you want, and you get it for free by following the rule of zero.
 
Ok, thanks a million! Time to rewrite all of this...
 
It may also be useful to add functions that serialize the class data - including those that have sub-structures and sub-classes within the class you are trying to serialize.

Depending on how clever you want to get you can set up macro's and do a lot of fancy stuff that sets up some structures in the class that allow procedures to serialize every thing without you having to write the individual code yourself. You could also just register variables with some global table as well.

If you ever want to save and restore your data easily then I would recommend checking out how to serialize your class data.
 

Similar threads

  • · Replies 40 ·
2
Replies
40
Views
4K
  • · Replies 25 ·
Replies
25
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
Replies
89
Views
6K
  • · Replies 35 ·
2
Replies
35
Views
4K
  • · Replies 23 ·
Replies
23
Views
3K
  • · Replies 31 ·
2
Replies
31
Views
3K
  • · Replies 118 ·
4
Replies
118
Views
9K
  • · Replies 2 ·
Replies
2
Views
2K
Replies
1
Views
1K