Question

#include <cstdlib>
#include <cstring>
#include <string>

using std::string;

string *arr_ptr;
int capacity;

void add() {
    int old_capacity = capacity;
    capacity <<= 1; 
    // double the capacity
    string *tmp_ptr = new string[capacity]; 
    // apply new space
    memmove(tmp_ptr, arr_ptr, sizeof(string) * old_capacity);
    // copy
    delete[] arr_ptr; 
    // free the original space
    arr_ptr = tmp_ptr;

    arr_ptr[capacity - 1] = "occupied";
    // without this statement, everything "seems" to be fine.
}

int main() {
    arr_ptr = new string[1];
    capacity = 1;
    for (int i = 0; i < 3; i++) add();
}

Run the code. As you can see, the program crashes when string's desctrutor is invoked. Try to comment the line of delete and check again.

I suspect that std::string keeps some address information of itself. It won't be informed when its location in memory has changed.

Furthermore, since memmove doesn't always work as expected, what's the appropriate expression of copying an array of class instance in C++?

Was it helpful?

Solution

memmove is a lowlevel function for copying bytes. This means that the value of an array of bytes is copied to another array. This is fine for POD data, but not for anything else. The reason is that classes can have a copy constructor, which isn't called by memmove and classes can have extra data like a vpointer for calling virtual member-functions.

The easiest solution for you is to replace memmove with std::copy for (#include <algorithm>) which copies entries instead of bytes:

std::copy(arr_ptr, arr_ptr + old_capacity, tmp_ptr);

OTHER TIPS

I believe what you are looking for is string::reserve.

In your code, you are also trying to make an array of string (and not a string as an array of character).

What you are doing here is copying the object 'string', and not its content (since you are not calling its constructor / destructor). Therefore, when you 'delete' your "arr_ptr", the destructor free the data associated. When you try to access it with tmp_ptr, the program segfault.

1st you don't initialize the value of your capacity as in:

int capacity;

should be:

int capacity = 0;

and when you try this operation:

arr_ptr[capacity - 1] = "occupied";

there is a referencing error that may occur.

The behaviour of this program is ::std::string implementation dependent.

If the implementation of string uses heap memory to store the characters, memmoveing an instance of string means there are two pointers pointing to the same heap memory. Calling the destructor of one of the string instance causes the heap memory to be freed, resulting in the other instance of string to have a dangling pointer.

So don't memmove strings :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top