尝试使用模板制作矢量

Trying to make a vector using templates

本文关键字:      更新时间:2023-10-16

我试图自学C++,但我又一次陷入了困境,似乎无法修复它。请原谅你即将看到的代码一团糟。这也是我在这个网站上的第一篇帖子,所以帖子的格式可能也会关闭,对不起。

有两个文件:main.cpp和vect1.h(没有vect1.cpp,因为模板似乎只挂在头文件中)


main.cpp:

#include <iostream>
#include "vect1.H"
using namespace std;
int main(){
    vect1<int> inst1(10);
    inst1[9]=4;
    cout<<inst1[9]<<endl;
    //-----
    vect1<double> inst2(10);
    inst2[5]=5.112;
    cout<<inst2[5]<<endl;
    //-----
    //====PART 2=====//
    cout<<"--------"<<endl;
    inst2[9]=999;
    cout<<inst2[9]<<endl;
    //inst2.pop();
    inst2.push(2);
    cout<<inst2[9]<<endl;
    cout<<inst2[10]<<endl;//New block
system("PAUSE");
return 0;}

vect1.h:

#ifndef VECT1_H
#define VECT1_H
#include <iostream> //DEBUG
template <class T>
class vect1{
private:
    T *ptr;
    T total; //work on this
    int units;
    int counter;
public:
    //vect1();
    vect1(T);
    vect1();
    T &operator[](const int &);
    void pop();
    void push(T);
};
//---------------------
/*
template <class T>
    vect1<T>::vect1(){
        ptr = new int [0];
    }
*/
template <class T>
    vect1<T>::vect1(T number){
        ptr = new T [number];
            total=0;
            units=(int)number;
        for(counter=0;counter<number;counter++){
            ptr[counter]=0;
        }
    }
    /* now the destruct is giving me errors...
template <class T>
    vect1<T>::~vect1(){
        total=0;
        delete[] ptr;
    }*/ //<<this line tosses a C2039 error
template <class T>
    T &vect1<T>::operator[](const int & ref){
        if(ref>0 && ref<(units)){
            return ptr[ref];
        }else{
            throw "Error! Out of range!"; //<<make catch 
        }
    }
//--------
template <class T>
    void vect1<T>::pop(){
        units = (units-1);
        T *tempPtr;
        tempPtr = new T[units];
            for(counter=0;counter<units;counter++){
                tempPtr[counter]=ptr[counter];
            }
        delete[] ptr;
        ptr = new T[units];
            for(counter=0;counter<units;counter++){
                ptr[counter]=tempPtr[counter];
            }
        delete[] tempPtr;
    }
//--
template <class T>
    void vect1<T>::push(T pushnum){
        units++;
        const int newsize=(int)units; //<<<<<
        T *tempPtr;
        tempPtr = new T[units];
            for(counter=0;counter<(units-1);counter++){
                tempPtr[counter]=ptr[counter];
            }
            //tempPtr[(int)units]=pushnum;
        delete[] ptr;
            std::cout<<units<<std::endl;//<<DEBUG
        ptr = new T[units];
            for(counter=0;counter<(units-1);counter++){
                ptr[counter]=tempPtr[counter];
                //ptr[9]=101;
            }
        ptr[newsize]=pushnum; /* <<bleh */
        //ptr[newsize]=12321; //DEBUG //<<Even this isn't working...
        delete[] tempPtr;
    }
//---------------------
#endif

输出(在控制台中):

4
5.112
--------
999
11
999
-6.27744e+066
Press any key to continue . . .

我们的计划是,当您pop()时,它将创建一个新的T临时数组,并将除最后一个块外的所有内容从原始数组复制到临时数组,删除原始数组,然后创建一个比以前小一个大小的新数组,并发送回所有内容,删除临时数组。推(数字)的想法是一样的,只是相反。Push会将自己复制到temp,Push会删除自己,然后将自己重新创建为大1号,然后将从temp到Push的所有内容都发送到Push并删除temp。然后将用Push发送的数字发送到新的块中。所以这个程序应该在第二行"999"之后打印出"2"。但我得到的却是"-6.27744e+066"。

Pop()似乎有效。排序。不过,推送(num)确实存在问题。我似乎也突然从我的析构函数中得到了C2039错误。它以前没有这样做过,我还没有改变其中的任何内容。

如果有人能看看这一团糟,给我一些解决问题的建议,我将不胜感激。谢谢

我使用Visual Studio 2010作为编译器。

这是我的构建日志(有一些不错的错误/警告!):

1>------ Rebuild All started: Project: chapter 16-5, Configuration: Debug Win32 ------
1>Build started 2/9/2012 5:34:01 PM.
1>_PrepareForClean:
1>  Deleting file "Debugchapter 16-5.lastbuildstate".
1>InitializeBuildStatus:
1>  Creating "Debugchapter 16-5.unsuccessfulbuild" because "AlwaysCreate" was specified.
1>ClCompile:
1>  main.cpp
1>e:programming(cpp)chapter 16-5chapter 16-5vect1.h(31): warning C4244: 'initializing' : conversion from 'double' to 'unsigned int', possible loss of data
1>          e:programming(cpp)chapter 16-5chapter 16-5vect1.h(30) : while compiling class template member function 'vect1<T>::vect1(T)'
1>          with
1>          [
1>              T=double
1>          ]
1>          e:programming(cpp)chapter 16-5chapter 16-5main.cpp(11) : see reference to class template instantiation 'vect1<T>' being compiled
1>          with
1>          [
1>              T=double
1>          ]
1>Manifest:
1>  Deleting file "Debugchapter 16-5.exe.embed.manifest".
1>LinkEmbedManifest:
1>  chapter 16-5.vcxproj -> E:Programming(CPP)chapter 16-5Debugchapter 16-5.exe
1>FinalizeBuildStatus:
1>  Deleting file "Debugchapter 16-5.unsuccessfulbuild".
1>  Touching "Debugchapter 16-5.lastbuildstate".
1>
1>Build succeeded.
1>
1>Time Elapsed 00:00:10.62
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
template <class T>
vect1<T>::vect1(T number){
    ptr = new T [number];
    total=0;
    units=(int)number;
    for(counter=0; counter<number; counter++) {
        ptr[counter]=0;
    }
}

此构造函数为number对象分配空间,但number具有常规类型T,并且您将其强制转换为int。如果您想要一个字符串或对象的向量,转换为int会失败。number应该具有int类型。通常不需要强制转换,并且它可能是糟糕设计的症状(继承-dynamic_cast除外)。

因为T可以是任何你不能在构造函数中初始化的东西,你必须把它留给向量的用户。


T &vect1<T>::operator[](const int & ref){

您使用const引用是因为您可能被告知它比传递值更快。对于较大的对象,这是正确的,而不是int。引用基本上只是另一个指针(具有不同的语法)。函数被传递一个地址给目标变量。指针和int通常都一样大,所以这里没有任何改进,通过指针访问肯定比直接访问值慢。


template <class T>
void vect1<T>::pop(){
    units = units-1;
    T *tempPtr = new T[units];
    for(counter=0;counter<units;counter++){
        tempPtr[counter]=ptr[counter];
    }
    delete[] ptr;
    ptr = tempPtr;
}

不需要将数据复制回ptr,只要复制指针就足够了。


template <class T>
void vect1<T>::push(T pushnum){
    units++;        
    T *tempPtr = new T[units];
    for(counter=0;counter<(units-1);counter++){
        tempPtr[counter]=ptr[counter];
    }
    tempPtr[units-1]=pushnum; // New item is at units-1 position!
    delete[] ptr;
    ptr=tempPtr; // Again, just assign the pointer.
}

并添加释放已分配内存的析构函数。

我希望这能有所帮助,我为我糟糕的英语感到抱歉。

我发现的直接问题是:

const int newsize=(int)units;
ptr = new T[units];
...    
ptr[newsize]=pushnum;

也就是说,您分配了newsize对象,但在这里您访问的是一个超出范围的值:只有索引0。。。newsize - 1可用。这也意味着您可能错过了初始化索引newsize - 1处的值,这可能导致您引用的值。

也就是说,我在查看代码时注意到了一些事情:

  1. 您不需要在push()函数中多次分配内存!只需创建一个足够大的数组,复制内容并将其放置到位即可。在可调整大小的向量的实际实现中,您会过度分配空间,并且只在内存耗尽时分配新内存。当重新分配时,你会使用一个大于1的系数(例如1.5或2)来确保你不会经常重新分配
  2. 分配内存的类也应该释放其析构函数中的内存,即需要实现析构函数。由于这种类型似乎也是可复制的,但默认生成的副本构造和副本分配做了错误的事情,因此还需要定义它们
相关文章:
  • 没有找到相关文章