【问题标题】:Template for resizing arrays调整数组大小的模板
【发布时间】:2017-07-12 23:27:37
【问题描述】:

我正在尝试为一类数组编写一个带有函数的模板类。 我将一些似乎适用于 int、float、double 的东西放在一起,但不适用于字符串。我包括了,并且正在使用命名空间标准。

除非我使用字符串,否则一切都可以编译,并且工作正常,在这种情况下,它会在 resize 函数中出错。

在头文件中我有以下相关代码(因为一切都编译并且错误只存在这里):

template<typename T>
void Array<T>::resize(int newSize)
{
    T* newArray = new T[newSize];
    if (newSize >= mSize)
    {
        for (int i = 0; i < newSize; ++i)
            newArray[i] = mData[i];
    }
    else
        for (int i = 0; i < mSize; ++i)
            newArray[i] = mData[i];
    delete[] mData;
    mData = new T[newSize];
    mSize = newSize;
    for (int i = 0; i < newSize; ++i)
        mData[i] = newArray[i];
    delete[] newArray;
    newArray = 0;
}

提前谢谢你。

【问题讨论】:

  • 错误是什么?
  • 你的代码看起来真的很多余,需要重构。
  • 我是一个新手,正在尝试使用我目前知道的工具进行学习。我知道通过练习我会变得更好、更有效率。

标签: c++ arrays string templates


【解决方案1】:

看看这段代码:

T* newArray = new T[newSize];
if (newSize >= mSize)
{
    for (int i = 0; i < newSize; ++i)
        newArray[i] = mData[i];
}

请注意,如果新大小大于旧大小,则从 0 迭代到 newSize 从旧数组中读取值。问题是旧数组只有从 0 到 mSize - 1 有效的索引,而不是从 0 到 newSize - 1,所以这会从数组的末尾读取。这在所有情况下都会导致未定义的行为(哎呀!),但对于原始类型,这通常不会导致崩溃,您只会在字符串中看到这种情况。

您可能需要查看其余代码以确保循环边界正确,因为我认为您会发现至少还有一个未正确设置的循环。

另外,请考虑查看valgrind 之类的工具,它们在诊断此类内存错误方面非常出色。

作为一个完整的偶然发现,您可能还想考虑是否需要进行两次分配和两次解除分配。您可以只使用一次新分配和一次解除分配来做到这一点吗?

【讨论】:

  • 除了 valgrind,我推荐使用 Clang Sanitizers。我个人更喜欢 Clang 的 Santizers 而不是 valgrind,其中一些在 gcc 中也很容易使用
  • 谢谢,有帮助。我查看了代码,我想我做错了什么是反转 newSize 和 mSize,我基本上没有迭代任何东西。我将其更改为:“如果更大,则写入设置新大小并写入我们所拥有的”,因此剩余索引为空,相反,当新大小较小时,仅“写入新大小”。现在可以使用了!
【解决方案2】:

假设mDataT* 类型,你可以试试这样:

template<typename T>
void Array<T>::resize(int newSize)
{       
    if (newSize == mSize) {
        return;
    }
    T* newArray = new T[newSize];
    if (newSize < mSize) {
        memcpy(newArray, mData, newSize * sizeof(T));
    } else {
        memset(newArray, 0, mSize * sizeof(T));
        memcpy(newArray, mData, mSize * sizeof(T));
    }
    delete[] mData;
    mData = newArray;
    mSize = newSize;
}

关键点:

  • 如果大小与之前相同,则无需调整大小!
  • 您只需复制一次,并且通过标准 memcpy 进行
  • 此函数与类型无关,可用于您的所有模板调整大小功能
  • 当调整大小的数组较大时,内存会使用 memset() 进行鞭打,以避免内存泄漏

【讨论】:

  • 不会std::fillstd::copy 基本上做同样的事情,除了更安全的类型?
  • 我试图用我现在知道的有限工具来编写它。还没学过memset/memcpy。我相信这些会让我的生活更轻松!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
相关资源
最近更新 更多