1

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.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
pirox22
  • 892
  • 1
  • 14
  • 30
  • 2
    If you define proper copy ctor you can use `Queries *q = new Queries( *oldq );` – Slava Jan 08 '16 at 15:55
  • Your thinking is correct. You need to pre-allocate `counter * sizeof(char)` bytes before copying the array. But you don't need an explicit loop to copy it - you can use `memcpy`. Alternatively, you may implement this as a [copy constructor](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three), as cited by Slava. – jweyrich Jan 08 '16 at 15:55
  • But how should I do the assignment in the array case inside the copy constructor? – pirox22 Jan 08 '16 at 16:18
  • Is this your struct or are you using some library code? If it's yours, I suggest using either `char*` or `std::string` instead of a zero-sized array (you should've gotten a warning in a C++ compiler). If it's from library API, take a look at [this](http://stackoverflow.com/questions/11733981/what-is-the-purpose-of-a-zero-length-array-in-a-struct) and [this](http://stackoverflow.com/questions/3350852/how-to-correctly-fix-zero-sized-array-in-struct-union-warning-c4200-without). – prazuber Jan 08 '16 at 16:21
  • Unfortunately, I am not allowed to change the structure of the struct, so changing char to stl's string is impossible. I '' ll check your links. Thanks – pirox22 Jan 08 '16 at 16:25

3 Answers3

2

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

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;
}
Community
  • 1
  • 1
prazuber
  • 1,352
  • 10
  • 26
0

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.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
  • I think this is wrong — you cannot assign a pointer (`new char[...]`) to a flexible-length array member (`char queries[]`). You could if it were `char *queries`, but that's not the question. – jwd Jun 17 '20 at 23:57