【问题标题】:Why this template class doesn't work properly?为什么这个模板类不能正常工作?
【发布时间】:2016-12-06 17:10:44
【问题描述】:
#include <bits/stdc++.h>
using namespace std;


template<class T>
class Array{
public:
Array(int sizeOfArray=1){
    arr = new T[sizeOfArray];
    for(int i=0;i<sizeOfArray;i++){
        arr[i] = 0;
    }
    maxSize = sizeOfArray;
    currentElement = 0;
}

T* growArray(){
    T* newarr = new T[maxSize*2];
    for(int i=0;i<maxSize;i++){
        newarr[i] = arr[i];
        }
    maxSize = maxSize*2;
    return newarr;
}

void add(T element){
    if(currentElement>=maxSize){
        arr = growArray();
    }
    arr[currentElement] = element;
    currentElement++;
}

T get(int index){
    return arr[index];
}

int nrElements(){
    return currentElement;
}

int length(){
    return maxSize;
}

~Array(){
    delete arr;
}
protected:

private:
T* arr;
int maxSize;
int currentElement;
};

template<class T>
Array<T> add(Array<T> &arr1, Array<T> &arr2){
int newsize = arr1.nrElements()+arr2.nrElements()+5;
int aux;
Array<T> arr3(newsize);
for(int i=0;i<arr1.nrElements();i++){
    aux = arr1.get(i);
    arr3.add(aux);
}
for(int i=0;i<arr2.nrElements();i++){
    aux = arr2.get(i);
    arr3.add(aux);
}
return arr3;
}

int main()
{
Array<int> arr(2);
for(int i=0;i<1000;i++){
    arr.add(i);
}

Array<int> arr2(2);
for(int i=1000;i<2000;i++){
    arr2.add(i);
}
Array<int> arr3;
arr3 = add(arr, arr2);
for(int i=0;i<arr3.nrElements();i++){
    cout<<arr3.get(i)<<" ";
}

return 0;
}

该功能正常工作。我的意思是上线 “辅助 = arr1.get(i);” 正在做它的工作,但是当我尝试在 main() 中读取 arr3 的元素时,前两个元素不是 0 和 1。程序显示的是其他大数字,例如 175243462 和 152614213。

【问题讨论】:

  • 建议不要对#include &lt;bits/stdc++.h&gt; using namespace std;使用高度谨慎
  • 看起来您可能遇到了三规则失败。 What is The Rule of Three?
  • 你每次都在泄漏内存arr = growArray()
  • 但是我怎样才能在不占用内存的情况下增加该数组呢?
  • 为了得到你期望的结果,定义 Copy-Constructor & Assignment Operator (但这里还有很多需要修复的地方,请参阅/了解std::vector implementation)为了避免内存泄漏,你需要在将新分配的内存指针分配给delete arr之前。

标签: c++ class-template


【解决方案1】:

OP 报告的错误可能是违反三规则的结果。 What is The Rule of Three?

template<class T>
Array<T> add(Array<T> &arr1, Array<T> &arr2)
{
    int newsize = arr1.nrElements() + arr2.nrElements() + 5;
    int aux;
    Array<T> arr3(newsize); <<- made a local array
    for (int i = 0; i < arr1.nrElements(); i++)
    {
        aux = arr1.get(i);
        arr3.add(aux);
    }
    for (int i = 0; i < arr2.nrElements(); i++)
    {
        aux = arr2.get(i);
        arr3.add(aux);
    }
    return arr3; <<- return by value. May trigger a copy of arr3, then destroy arr3
}

没有复制构造函数或赋值运算符,因此编译器生成的默认方法是......非常简单。他们盲目地调用其成员变量的复制和赋值运算符,并且指针的默认复制行为是复制内存位置而不是指向的内存。这意味着副本和源的arr 成员都指向同一个内存位置。 Array 析构函数delete arr;,所以现在剩下的副本指向已释放的内存。访问任何副本现在是未定义的行为,并且销毁任何副本将导致双重删除。非常糟糕的场景。

解决方案,无论如何,对于这个错误,实现复制构造函数和赋值运算符。这里有一些帮助:Operator overloading

奖励错误:

void add(T element)
{
    if (currentElement >= maxSize)
    {
        arr = growArray(); <<- did not release the old array pointed at by arr
    }
    arr[currentElement] = element;
    currentElement++;
}

add 泄漏内存,因为它在替换arr 之前没有delete arr 这在add 中比在growArray 中更难做到(诚然不是很多)所以,

void growArray() <<- returns nothing
{
    T* newarr = new T[maxSize * 2];
    for (int i = 0; i < maxSize; i++)
    {
        newarr[i] = arr[i];
    }
    maxSize = maxSize * 2;
    delete arr; <<- clean up old arr
    arr = newarr; <<- assign arr here
}

void add(T element)
{
    if (currentElement >= maxSize)
    {
        growArray(); <<- everything done by growArray
    }
    arr[currentElement] = element;
    currentElement++;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 2023-02-20
    • 1970-01-01
    相关资源
    最近更新 更多