Copying struct's dynamic array to another struct - c++

I have a struct defined like this:
struct Queries {
uint64_t Id;
uint64_t from;
uint32_t counter; // total queries
char queries[];
};
What I am trying to do is create a new struct "object" and copy the values from an existing one to this new object.
What I tried
void function(Queries* oldq){
Queries* q = new Queries();
// values are copied correctly
q->Id = oldq->Id;
q->from = oldq->from;
q->counter = oldq->counter;
// copy is not correct
for (unsinged i = 0; i < oldq->counter; i++)
q->queries[i] = oldq->queries[i];
}
1) I also tried:
q = oldq;
but this does not work.
2) I think I have to allocate counter * sizeof(char) space for the queries array but since the struct's member is not a pointer I don't know how to do this.

Here you are dealing with a C-style flexible array member. It's not valid C++ code, but it is valid C since C99 (see link for details). To use such structure, you need to allocate sizeof(Queries) + counter bytes, where the array field will use that counter bytes part. (Note: if you had array field other than char you would have to multiply accordingly.)
Now, you cannot use C++ features here like copy constructor since compiler doesn't know the size of your structure. Instead, you have to use the pure C approach:
Queries *cloneQueries(Queries *oldQ)
{
size_t sizeQ = sizeof(Queries) + oldQ->counter;
Queries *newQ = (Queries*)malloc(sizeQ);
memcpy(newQ, oldQ, sizeQ);
return newQ;
}

The simplest thing to do is to use a std::string for queries.
Then you can simply write Queries* q = new Queries(*oldq); and rely on the compiler-generated constructor: you can remove all your copying code.

You could do it by using copy constructor that performs a deep copy of your object.
This could be done when instead of function() you define a copy constructor like so:
Queries(const Queries& q)
: Id(q.Id), from(q.from), counter(q.counter)
{
// allocate the new memory
queries = new char[counter];
// copy each element
for (size_t i = 0; i < counter; ++i) {
queries[i] = q.queries[i];
}
}
and then in your code, you could use the line:
Queries *q = new Queries(*oldq);
where the object on the right hand side is created by copy construction, i.e. by copying the object oldq.
See, how operator new[] works.

Related

Appending struct by reference to an array in C++

How can I implement a function in C++ that appends a struct instance to an array by reference? So that after appending a struct stored in a variable to the array, this variable can be used further to change the instance of array.
pseudocode:
struct St{
int x
}
St* arr;
St a = {0};
append a to arr;
a.x = 1;
//expecting arr[0].x = 1
Here is the C++ code with the film example (see comments describing the problem):
struct Film{
int id;
char* name;
};
void add_film(Film *&films, int &size, Film &film){
if (size == 0)
films = new Film[1];
else
{
Film *tmp = new Film[size + 1];
for (int i = 0; i < size; ++i)
{
tmp[i] = films[i];
}
delete[]films;
films = tmp;
}
films[size] = film;
film = films[size]; //how to reassign passed film object to a new object in array?
size++;
}
int main(){
Film *films = nullptr;
int size = 0;
Film film = {1, "Name1"};
add_film(films, size, film);
film.name = "Name2";
std::cout << films[0].name; //output: "Name1", expected: "Name2"
}
Appending struct by reference to an array in C++
There are two problems with this:
There cannot be arrays of references in C++.
There is no way to append to an array. The size of an array is a constant. There is no way to add or remove elements.
An issue with your attempted solution is that you have an array of Films, and not an array of references. This isn't very surprising, as problem 1 described above states there are no such thing as arrays of references. The solution is simple however: Use pointers instead of references. Technically, you could use a reference wrapper instead, but a pointer is often simpler.
You've basically figured out the solution to 2. already. What you're doing is creating a new array, copying the old elements from the old array into the new one, and destroying the old array. That's a good approach in general, but there are a number of problems with this trivial implementation:
Bare owning pointers are unsafe and hard to use.
Reallocating and copying the entire array on every append is very expensive.
Former can be solved by using the RAII idiom, and latter can be solved by separating the storage of the objects from the creation of the objects, and by growing the storage by a constant factor i.e. geometrically. There is no need to implement such RAII container though, since the standard library has you covered. It's called std::vector.
In conclusion: You can use std::vector<Film*>.

C++ dynamic array of pointer to another class

Hello i'm trying to create a dynamic array of pointer to an object Student from Gradesclass but i can't figure out how to declare it in the header
that's the header:
class Grades
{
private:
Student** array;
int _numofStud;
public:
Grades();
Grades(const Grades& other);
~Grades();
and the grades constructor (i'm not sure it's right)
Grades::Grades()
{
this->array = new Student * [2];
for (int i = 0; i < 2; ++i)
{
this->array[i] = NULL;
}
this->array[0]= new Student("auto1", "12345");
this->array[1]= new Student("auto2", "67890");
this->_numofStud = 2;
}
The probleme is that before it even enter to the constructor, it creating me an array of Size 5 in Grades because i have 5 elements in the Student constructor
Student::Student(const char* name, char* id)
{
this->_numofgrade = 0;
this->setName(name);
this->setId(id);
this->_grades = NULL;
this->_average = 0;
}
And i can't add or modify this size
I want to put a default size of Grades to an array of 2 pointers to student object that i'll define as default then i'll have an other methods that add new Students by creating them and adding their pointers to the array
Th problem is i can't change the size of array and i don't understand why
I hope i was clear in my explanation thanks for your help
Edit:
that's the debuger and you can see when it's creating a new object Grades g1
it's creating an array of 5 instead off two
fill the 2 first as i asked for
and the 3 left i have no idea why they have been created and whats inside them
OK, so to be clear, in any actual programs you should use std::vector or other containers, they have a lot of features I ignored here (being templates, supporting move semantics, not requiring a default constructor, etc.), a lot of saftey (what if a constructor throws an exception? What if I do array.add(array[0])?), while still being pretty well optimised for general purpose usage.
And you should also really look at std::unique_ptr, manual new, delete, is generally asking for leaks and other mistakes, in C++ a manual "free" or "delete" of any resource is almost never needed.
Also note in C++ size_t is often used for sizes/lengths of objects and containers.
So the basic idea of a dynamic array is it changes it's size based on current requirements, so Grades() can just start off empty for example.
Grades::Grades()
: array(nullptr), _numofStud(0)
{}
Then when adding a new item, a new larger array is made, and all the existing items are copied (roughly what std::vector::push_back(x) does).
void Grades::addStudent(Student *student)
{
// make a larger array
Student **newArray = new Student*[_numofStud + 1];
// copy all the values
for (int i = 0; i < _numofStud; ++i)
newArray[i] = array[i]; // copy existing item
// new item
newArray[_numofStud] = student;
++_numofStud;
// get rid of old array
delete[] array;
// use new array
array = newArray;
}

how can I copy an array from a class and double the size of the new array?

CDCatalogue::CDCatalogue() //creates array of size 4
{
maxsize=4;
numcds = 0;
cds = new CD[maxsize];
}
I want this to copy cat into a new array with double the size of cat:
CDCatalogue::CDCatalogue(const CDCatalogue& cat)
{
}
As suggested before I'd prefer to use std::vector, which offers the resize() member function for exactly what you need. This is probably what you are looking for.
If for some reason you cannot use vectors, maybe a simpler approach than having a "doubler copy constructor" would be having a function 'doubleSize' that you can call right after construct-copying.
Assuming that in your example in the question, maxsize and cds are declared as class members, you could do something like this:
CDCatalogue::doubleSize() {
unsigned int oldMaxSize = maxsize;
maxsize *= 2; // You might want to keep an eye for overflows here
CD *oldCds = cds;
cds = (CD*) new CD[maxsize];
std::copy(oldCds, oldCds+oldMaxSize, cds);
delete[] cds;
}
Note that this is not as simple as using vectors, because there is no "resize" for c++ dynamic allocations. Instead, you have to create a new array of the new desired size, copy the elements of the old array into the new, and then release the memory of the old array. Note that the last half of elements of the new array will be initialized to undefined values.

C++ Pointer of Array of Ints Initialization

I want to have an array accessible by all functions of a class.
I put the array as private variable in the header file.
private:
int* arrayName;
In the .cpp file where I implement the class, the constructor takes in an int value (size) and creates the array. The goal is to fill it up
ClassName::ClassName(int numElements){
arrayName = new int[numElements]; //make arrays the size of numElements
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
}
I feel like this is quite inefficient. I know you can do int array[5] = {0}; but how do you do it when you don't initially know the size.
If you want to zero-initialize a newed array, just do value-initialize it. This has the effect of zero-initializing its elements:
arrayName = new int[numElements]();
// ^^
But you really want to be using an std::vector<int>.
private:
std::vector<int> vname;
and
ClassName::ClassName(int numElements) : vname(numElements) {}
This way you don't have to worry about deleting an array and implementing copy constructors and assignment operators.
You can use the memset function:
memset(arrayName,0,sizeof(int)*numElements);
This void * memset ( void * ptr, int value, size_t num ); function sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).
To use it you must include the string.h header file.
For more information: http://www.cplusplus.com/reference/cstring/memset/
What you want to do is progressively expand the array on demand.
arrayName = new int[numElements];
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
The above code (what you gave) will give you an array of size numElements, and THEN the for loop will fill it. This is allocated now, and can't, as I understand it, be simply or easily resized (memset will overwrite previously held values in the array).
You could copy the whole array over every time you want to resize it:
int * oldarr = new int[OldSize];
//fill your old array
int * newarr = new int[NewSize];
for(int i = 0; i<OldSize; i++)
newarr[i] = oldarr[i];
Other than that, you could make the array much larger, or you could use various STLs, such as std::vector. Vector can be increased with a simple push_back function, and allows [] operator access (like arr[5] and whatnot).
Hope this helps!

Using a constructor for an array of structures

I want to create an array of structures. The structure uses a constructor as shown below:
struct struct_seedinfo {
struct_seedinfo(const mxArray *prhs[ ],const int seed_id){
mxArray *mat_coords, *mat_defvectorinit, *mat_corrcoef, *mat_roi_id;
mat_coords = mxGetField(prhs[1],seed_id,"coords");
coords = mxGetPr(mat_coords);
mat_defvectorinit = mxGetField(prhs[1],seed_id,"defvectorinit");
defvectorinit = mxGetPr(mat_defvectorinit);
mat_corrcoef = mxGetField(prhs[1],seed_id,"corrcoef");
corrcoef = *(mxGetPr(mat_corrcoef));
mat_roi_id = mxGetField(prhs[1],seed_id,"roi_id");
roi_id = *(mxGetPr(mat_roi_id));
}
double *coords;
double *defvectorinit;
double corrcoef;
double roi_id;
static int num_seeds;
};
How could I create an arbitrary sized array of this structure? I need to allocate memory for it, but it seems like I would need to allocate memory without calling the constructor, and then call the constructor later in a forloop. Is there a good or preferred way of doing this? Thanks.
You can do std::vector<struct_seedinfo>. This will create an array and it will automagically increase in size when needed.
You'll also need to overload the copy constructor and copy-assignment operator for your struct to be able to be used in a vector. You need a destructor too. This is called the Rule of Three in C++
Well since the size stay constant, you can use the following solution :
*This assumes your ok with defining a default constructor.
First declare a default constructor in your class.
struct_seedinfo(){
//If you want to initlaize something.
}
Than you can use the following to create you array :
struct_seedinfo * arr = new struct_seedinfo[size_of_array];
And then you need for each space to do your specific build :
arr[i] = struct_seedinfo(//arguments);
This is if you badly need an array, i do also think the vector solution is better.