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.

5
  • 2
    If you define proper copy ctor you can use Queries *q = new Queries( *oldq ); Commented Jan 8, 2016 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, as cited by Slava. Commented Jan 8, 2016 at 15:55
  • But how should I do the assignment in the array case inside the copy constructor? Commented Jan 8, 2016 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 and this. Commented Jan 8, 2016 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 Commented Jan 8, 2016 at 16:25

3 Answers 3

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;
}
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

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.

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.