1
#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();
}

运行代码。如您所见,调用字符串的析构函数时程序崩溃。尝试评论该行delete并再次检查。

我怀疑 std::string 保留了自己的一些地址信息。当它在内存中的位置发生变化时,它不会被通知。

此外,由于memmove并不总是按预期工作,在 C++ 中复制类实例数组的适当表达是什么?

4

4 回答 4

2

memmove是用于复制字节的低级函数。这意味着一个字节数组的值被复制到另一个数组。这适用于POD数据,但不适用于其他任何数据。原因是类可以有一个复制构造函数,它不会被 memmove 调用,并且类可以有额外的数据,比如用于调用虚拟成员函数的 vpointer。

对您来说最简单的解决方案是memmovestd::copyfor ( #include <algorithm>) 替换它复制条目而不是字节:

std::copy(arr_ptr, arr_ptr + old_capacity, tmp_ptr);
于 2013-06-06T09:28:45.263 回答
1

我相信您正在寻找的是string::reserve

在您的代码中,您还试图创建一个字符串数组(而不是将字符串作为字符数组)。

您在这里所做的是复制对象“字符串”,而不是其内容(因为您没有调用其构造函数/析构函数)。因此,当您“删除”您的“arr_ptr”时,析构函数会释放相关的数据。当您尝试使用 tmp_ptr 访问它时,程序段错误。

于 2013-06-06T09:32:36.057 回答
0

首先,您没有初始化您的容量值,如下所示:

int capacity;

应该:

int capacity = 0;

当您尝试此操作时:

arr_ptr[capacity - 1] = "occupied";

可能会出现引用错误。

于 2013-06-06T06:42:27.423 回答
0

该程序的行为::std::string取决于实现。

如果 string 的实现使用堆内存来存储字符,那么memmoveing 一个 string 的实例意味着有两个指针指向同一个堆内存。调用其中一个字符串实例的析构函数会导致堆内存被释放,从而导致字符串的另一个实例有一个悬空指针。

所以不要memmove串:)

于 2013-06-06T07:00:18.977 回答