How to copy a structure with pointers to data inside? - c++

I am using the CUDD package for BDDs manipulation.
I want to make a copy for a big data structure in it that is called the DdManager.
The problem is : this data structure has so many pointers inside it , so when I make a direct copy it is a "shallow" copy(as some use the term) i.e. : the pointers in the new copy point to the same places pointed to by the original copy , so when I change in anyone of them I also change in the other which is undesirable ....
Trying to make a copy function by hand is not feasible because the data structure is really big and very detailed with many pointer to other complex structures also !!!
I have tried the vector solutions described here but I did not get the expected result because there are many nested structures and pointers and I want a completely new copy.
Here is a code sample of what I want to do :
#include <iostream>
#include <cstdlib>
#include <string.h>
#include <vector>
using namespace std;
struct n1
{
int a;
char *b;
};
struct n2
{
int **c;
struct n1 *xyz;
};
typedef struct
{
vector<struct n2> x;
}X;
int main()
{
struct n2 s1;
s1.xyz = (struct n1*)malloc(sizeof(struct n1));
s1.xyz->a = 3;
s1.xyz->b = (char*)malloc(5);
s1.xyz->b[0] = '\0';
strcat(s1.xyz->b,"Mina");
s1.c = (int**)malloc(5 * sizeof(int*));
for(int i = 0; i < 5; i++)
s1.c[i] = (int*)malloc(5 * sizeof(int));
for(int i = 0; i < 5; i++)
for(int j = 0 ; j < 5 ; j++)
s1.c[i][j] = i + j;
X struct1,struct2;
vector<struct n2>::iterator it;
it = struct1.x.begin();
it = struct1.x.insert(it,s1);
it = struct2.x.begin();
it = struct2.x.insert(it,struct1.x[0]);
cout<<"struct2.x[0].c[1][2] = "<<struct2.x[0].c[1][2] <<" !"<<endl; // This is equal to 3
(struct2.x[0].c[1][2])++; //Now it becomes 4
cout<<"struct2.x[0].c[1][2] = "<<struct2.x[0].c[2][2] <<" !"<<endl; //This will print 4
cout<<"s1.c[1][2] "<< s1.c[1][2]<<" !"<<endl; // This will also print 4 ... that's the wrong thing
return 0;
}

Despite other saying that you have to
make a copy function by hand
...to solve this, I think that's the wrong approach for you. Here's why, and here's a suggestion.
You're trying to create a copy of a CUDD ddManager object, which is an integral part of the complex CUDD library. CUDD internally uses reference counts for some objects (which might help you here...) but the ddManager object effectively represents an entire instance of the library, and I've no ideas how the reference counts would work across instances.
The CUDD library and it's associated C++ wrapper doesn't seem to provide the necessary copy constructors for creating separate copies of the ddManager, and to add these would probably involve serious effort, and detailed internal knowledge of a library that you are just trying to use as a client. While it's possible to do this, it's complex thing to do.
Instead, I'd look at trying to write out the current BDD to a file/stream/whatever, and then read it back into a new instance of a ddManager. There's a library called dddmp that should help you with this.
I'd also recommend that the C++ wrapper was modified to make the ddManager class non-copyable.

"Trying to make a copy function by hand is not feasible because the data structure is really big and very detailed with many pointer to other complex structures also !!! "
This is exactly what you have to do.
The objective approach means that you don't write one big do-it-all copy method. Instead, every object (structure) copies only itself, and then call it's sub-object copy methods, etc, etc until there is nothing more left to copy.
There is no such thing as "vector solution", vector is simply the smallest object with it's smallest copy method.
There is no difference between struct and class, so just write them copy methods.
Only you know the structure of your data, so you're the only One who can save the humankind (or copy this data).

Related

C++ default behavior for arrays - shallow copies?

As the title says - I need the content of the v array not to change outside of the function.
I thought that it would not happen (because AFAIK the default behavior of arrays is to deep copy - but it looks like it is not).
#include <iostream>
using namespace std;
void testModif(int *v)
{
for (int i = 0; i < 5; i++)
{
v[i]++;
}
}
int main()
{
int *v;
v = new int[100];
*v = 0;
testModif(v);
for (int i = 0; i < 5; i++)
{
cout << v[i] << " ";
}
}
How can I make v not change after running testModif?
First you can enlist the compilers help by declaring as
void testModif(const int *v);
I.e. as v being a non-const pointer to const int. I.e. you can e.g. increment the copy of the pointer, but not change what the pointer points to.
With that change the shown code will get errors/warnings, which at least tell you that you are doing what you do not want to do.
Then you need to change your code to follow your self-decided rule.
For the shown code that would require making a copy of the array itself (not only of the pointer pointing to it). Exactly, that would match "deep copy" in contrast to the "shallow copy" you mention.
Most closely to your shown code would be a local copy, an array of size 5 (magic number, but you know what I mean) or something malloced of proper size (and of course freed before leaving the function).
Obviously making a local copy, incrementing all members and then leaving the function again normally would seem pointless. I trust that this is purely to be blamed to you making an appropriate MRE. I.e. the point that intentionally not changing the original values and only locally incrementing is what you want to achieve.
Of course I am not contradicting the comments to your question, which recommend the more C++ way of doing things, with standard containers, like std::array, std::vector.

How to copy the data of an array of pointers in C++

I'm trying to copy the data present in an array of pointers to another one.
I have very few knowledge in C++, but some in higher level languages.
Here is a sample code of what I've achieved so far (simplified version):
#define MAX_ACTIVE_MODES 3
myStruct_t priorities1[MAX_ACTIVE_MODES];
myStruct_t *priorities2[MAX_ACTIVE_MODES];
for (unsigned short i = 0; i < MAX_ACTIVE_MODES; ++i) {
priorities2[i] = (myStruct_t*)malloc(sizeof(myStruct_t));
memcpy(priorities2[i], &priorities1[i], sizeof(myStruct_t));
}
// ...
delete[] *priorities2;
It's easier for me to have a non pointer var for priorities1 and have one for priorities2 because I'm passing it to a sort function.
When I search for solutions, there's never the case of type *var[] and I don't get why.
Even though your question is tagged c++, I assume that you are programming in C based on your use of malloc.
First you don't need to use memcpy to copy structs.
*priorities2[i] = priorities1[i];
should be equivalent to
memcpy(priorities2[i], &priorities1[i], sizeof(myStruct_t));
Second, you don't have to create copies of the elements in priorities1[]. Just have the pointers in priorities2[] point to the elements in priorities1[]:
for (size_t i = 0; i < MAX_ACTIVE_MODES; ++i)
{
priorities2[i] = &priorities1[i];
}
As long as you don't access priorities2 beyond the lifetime of priorities1, no malloc or free is needed.

Vector in c++ using for loop

I am new to c++ in general. So I have been trying to learn about using vectors after someone recently helped with using an Arduino type project to read RFID tags. It really got me thinking I have no clue how to program. So I hit the books!
So here is the question: When I do the following code:
#include <iostream>
#include <vector>
struct Runner{
char runnerTag[32];
uint32_t ts;
};
std::vector<Runner > runners;
int main() {
std::cout << "Hello, Runners!\n";
for (int i = 0; i < 100; i++) {
std::string runnertg = "testTrackTag01";
uint32_t timeStamp = rand() % 100 + 1;
runners[i] = new Runner({runnertg, timeStamp});
}
return 0;
}
I get this annoying little message from xcode:
No matching constructor for initialization of 'Runner'
on line 16 of the above snippet. What in the world am I doing wrong?
The expression new Runner({runnertg, timeStamp}) has a type mismatch. runnertg is of type std::string, while the element Runner::runnerTag is of type char[32].
The expression runners[i] = new Runner({runnertg, timeStamp}); has another type mismatch. The element type of runners is Runner, while the expression new Runner({runnertg, timeStamp}) is of type Runner*.
runners[i] is out-of-bound access. The size of runners is 0. The elements runners[i] for all values of i does not exist.
There is memory leak since there is no matching delete for each new for all code path.
Don't use rand().
A lot of the code you're using is old style C with some C++ STL code mixed in. I will try and tackle a few issues one at at time.
struct is an abstract data type used (in general) to organise primitive data types. While the only difference between a struct and a class is that the latter defaults all members to private and in this case is not functional, it's a good to cut these things of at the pass.
Secondly, an array of chars is cumbersome, messy and prone to error. Try an std::string instead.
Finally, let's create a constructor taking our two parameters.
Thus:
#include <string>
class Runner {
public:
std::string runnerTag;
uint32_t ts;
Runner(std::string, uint32_t);
};
Next thing. Using an array index operator [] to access or modify an std::vector is dangerous and defeats the purpose of using a container and all the wonderful functionality that comes along with it.
Since you know for loops, let's try this:
for (int i = 0; i < 100; i++) {
std::string runnertg = "testTrackTag01";
uint32_t timeStamp = rand() % 100 + 1;
Runner Runner(runnertg, timeStamp);
runners.push_back(Runner);
}
At the end of your code, outside the scope of the main function, define the constructor as follows:
Runner::Runner(std::string rt, uint32_t ts) {
runnerTag = rt;
ts = ts;
}
This should get you started.
You cannot convert std::string to a char array like that. Change the type of the member variable runnerTag to std::string. Also, you are accessing vector elements that don't exist. Use resize to create them. Or better yet, use emplace_back to do both at once. Also, don't use int to iterate containers, but std::size_t. Also, don't use rand(), but the classes from the <random> header. That trick using % creates a non-uniform distribution.

Object not added to array

I'm doing my homework (and learn how C++ works).
My task is:
Define some class with field...(never mind)
create an vector and array from these object and iterate it! (listing, average by field,etc).
Now it's correctly works with vector, but array doesnot work:
static Cipo* cipok; // object array
static int cep = 0; // endpoint index
static int ccap = 0; // array size
Default assignmet opearator for Cipo:
public: Cipo& operator=(const Cipo &c)
{
return ((Cipo&)c);
}
Initalization:
cipok = (Cipo*) malloc(sizeof(Cipo*)*100); // new Cipo[num] doesn't work..
ccap = 100;
Test code:
for (int i = 0; i < 5; i++)
{
Cipo c(43.5, "str", 12670, false, false);
std::cout << c.ar <<" ";
cipok[cep] = c;
std::cout << cipok[cep].ar << " ";
cep++;
}
And the result:
12670 0 12670 0 12670 0 12670 0 12670 0
But objects not "disappeared" if I use vector, push_back() the objects and read from the vector with direct indexing (or with iterators). Why do they exhibit this behaviour?
You immediate problem is likely caused by whacky implementation of operator = that does absolutely nothing. I'd recommend step through the code in debugger to see it. operator = (and copy constructor) should properly copy values into destination object.
There are many other issues with the code - your naming convention is ... interesting, you seem to try to cast whatever you have to whatever result is required for code to compile without reasoning what should actually be done. malloc in C++ code is very rarely needed...
I think the general problem is, I'm programming always in java (but now in university i must prog. in C/C++, naming conventions, like in java and in hungarian the Cipő is meaning Shoe). And in Java there is no pointers, and all object always acces by reference, but looks like (as i tested ) if i create a new object array the C++ will not allocate only 100 pointer which points to the object (where the object data starts), it allocated 100*sizeof(object) and for this place i can add data trougth assing operator.
it's my teory true?
So i tried to manage Object acces like in java.
Why copy the Object if itself alredy exist? (I don't like to "clone" objects).

tictactoe and copying an array

Hello I am working on a tic-tac-toe project on my own. I am not taking a programming class so its not homework.
I have written pretty much the rest of the code and am now working on the AI.
For the AI i am going to have it take a copy of the (2 dimensional array) and it check if it can win in a move, then if the player can, then if it can in 2 moves, then the player and so on, there are some other things i will include. So in order to do this i think i need to pass a copy of the array, but i am not sure how to copy an array. So that is basically my question, how do you copy an array?
You can wrap the array into a class, in which case it'll be copied automatically by the default-generated copy constructor and assignment operator:
enum EField { empty, cross, oh };
typedef std::array<EField, 9> TTTBoard; // C++11, or use std::tr1::array
Or do it manually:
struct TTTBoard
{
EField data[9]; // or even EField data[3][3]
};
Now you can copy it at will:
TTTBoard b;
TTTBoard c = b;
A neat trick you could do without concerning yourself with array copying is to create a type for your 3x3 board:
struct TicTac{
int board[3][3];
}
And just pass that as the argument to your function.
What kind of array do you have?
I'm assuming you have the plain old school integer array.
when you have:
int Array[3][3];
then to copy it's contents to another array you will have to loop each element.
this can be done like this:
int MyArray[3][3];
int CopyHere[3][3];
for(int i = 0; i < sizeof(MyArray); ++i)
{
for(int j = 0; j < sizeof(MyArray[i]); ++j)
{
CopyHere[i][j] = MyArray[i][j];
}
}
I have somewhere an old TicTacToe script, lemme look for it.
Edit: found it:
http://pastebin.com/Xp5iT2b0
Here is the related topic:
http://forum.sa-mp.com/showthread.php?t=259549