#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();
}
运行代码。如您所见,当调用string的desctrutor时程序崩溃。尝试评论delete
的行并再次检查。
我怀疑std :: string会保留一些自己的地址信息。当它在内存中的位置发生变化时,它不会被告知。
此外,由于memmove
并不总是按预期工作,因此在C ++中复制类实例数组的适当表达是什么?
答案 0 :(得分:1)
memmove
是用于复制字节的低级函数。这意味着将字节数组的值复制到另一个数组。这适用于POD数据,但不适用于其他任何内容。原因是类可以有一个复制构造函数,memmove不会调用它,类可以有一些额外的数据,比如用于调用虚拟成员函数的vpointer。
最简单的解决方案是将memmove
替换为std::copy
(#include <algorithm>
),复制条目而不是字节:
std::copy(arr_ptr, arr_ptr + old_capacity, tmp_ptr);
答案 1 :(得分:1)
我相信你要找的是string::reserve。
在你的代码中,你也试图创建一个字符串数组(而不是字符串作为字符数组)。
你在这里做的是复制对象'string',而不是它的内容(因为你没有调用它的构造函数/析构函数)。 因此,当您'删除'您的“arr_ptr”时,析构函数释放相关的数据。 当您尝试使用tmp_ptr访问它时,程序会出现段错误。
答案 2 :(得分:0)
1,您没有初始化您的容量值,如:
int capacity;
应该是:
int capacity = 0;
当您尝试此操作时:
arr_ptr[capacity - 1] = "occupied";
可能会发生引用错误。
答案 3 :(得分:0)
此程序的行为依赖于::std::string
实现。
如果字符串的实现使用堆内存来存储字符,memmove
字符串实例意味着有两个指向同一堆内存的指针。调用其中一个字符串实例的析构函数会导致释放堆内存,从而导致另一个字符串实例具有悬空指针。
所以不要memmove
字符串:)