0

假设我想调整一个 int 指针数组的大小,我有一个看起来像这样的函数

    template<typename T>
static void Resize(T* arr, UINT oldsize, UINT newsize) {
    T* ret = new T [newsize];
    memcpy(ret, arr, sizeof(arr[0]) * oldsize);
    delete[] arr;   
    arr = ret;
};

当我尝试调整使用“new”关键字创建的元素数组(即使类内的数据本身是 POD)时,问题就开始了,因为 delete[] 触发了它们的解构函数,然后将新数组留下指向不再存在的对象。所以.. 即使对象是用“new”创建的,我不能只使用 free 命令来摆脱旧数组吗?或者以某种方式删除数组而不触发每个成员的解构器?

4

3 回答 3

4

使用std::vector.


编辑:根据大众的需求,解释为什么 OP 的代码不起作用

编码:

template<typename T>
static void Resize(T* arr, UINT oldsize, UINT newsize) {
    T* ret = new T [newsize];
    memcpy(ret, arr, sizeof(arr[0]) * oldsize);
    delete[] arr;   
    arr = ret;
};

arr是一个按值传递的指针。最后分配给arr只会更新实际参数的本地副本。因此,在此之后,调用代码中的实际参数指向一个已为deleted 的数组,结果非常糟糕!

可以通过引用传递该指针来拯救它:

template<typename T>
static void Resize(T*& arr, UINT oldsize, UINT newsize) {
    T* ret = new T [newsize];
    memcpy(ret, arr, sizeof(arr[0]) * oldsize);
    delete[] arr;   
    arr = ret;
};

但这仍然是非常脆弱的代码。

例如,调用者需要跟踪数组大小。

使用std::vector被调用a,调整大小调用看起来像

a.resize( newSize )

与 DIY 解决方案相比,当newSize更大时,向量的那些额外元素将被归零(这比将它们保留为不确定值更安全一些)。

Astd::vector可以像原始数组一样被索引。有关如何使用它的更多详细信息,请参阅您的C++ 教科书。如果您还没有 C++ 教科书,那就买一本吧:对于大多数人来说,从网络上的文章和问答中学习 C++ 只是一个不切实际的提议。

于 2012-11-28T23:32:26.213 回答
2

对于它的价值,您尝试做的事情并不是一件非常糟糕的事情,而且有时它是有道理的,但它根本不被newand delete(或new[]and delete[])提供的接口所支持。正如其他人所说,它malloc, free, 和支持realloc(警告realloc将在重新分配时复制指针值,但不能保证新区域中的指针被初始化为任何有用的东西,例如NULL)。

因此,事不宜迟,适用于几乎所有人的最简单答案是使用 astd::vector<int>而不是尝试自己管理内存。矢量具有调整大小的能力,当它调整大小时,它会复制需要复制的东西。 std::vector存在以提供“可调整大小的数组”并为您管理内存。实际上,如果你想要一个指针容器,你最好使用std::vector<std::unique_ptr<T>>/ std::vector<std::shared_ptr<T>>(在 C++11 中)或来自Boost Pointer Container的东西。

值得一提的是,原来的 STL 没有使用new[]delete[]实现std::vector<T>. 通常,操作系统提供的内存远远超过您的要求。例如,如果我尝试使用malloc16 个字节,我返回的块很可能是 1024 个字节。我可以用它来存储四个 32 位整数。当我用完空间时,我可能会要求 32 个字节,并得到一个不同的 1024 字节块,我可以将我的四个整数复制到其中。但是,当原始块实际上大到可以开始时,为什么还要麻烦要求一个新块来保存我的整数呢?不幸的是,new[]不要delete[]提供一种方式来说“给我一个至少有这么大的块,顺便说一下,这里有一个可能已经足够大的块”。 realloc有点像。 Facebook Folly 包含一个std::vector不使用new[]or的类似容器delete[](请注意,它也不使用realloc任何一个,因为它通常不适用于对象容器;相反,它使用mallocand 非标准函数malloc_usable_size),并且Firefox 通过以类似方式管理内存的麻烦。

即便如此,我不鼓励试图变得棘手。 std::vector有很多满意的用户。

于 2012-11-29T00:18:56.290 回答
1

我认为在删除之前使数组中的所有元素都指向 NULL 应该可以完成这项工作。但是,如果您可以使用 STL,那么 std::vector 会让您的生活更轻松(正如 Alf 建议的那样:P)。

于 2012-11-28T23:55:09.900 回答