Попытка сделать вектор, используя шаблоны - PullRequest
2 голосов
/ 10 февраля 2012

Я пытаюсь самообучаться на 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 и удаляет temp. Затем отправьте номер, отправленный нажатием, в новый блок. Таким образом, эта программа должна вывести «2» после второй строки «999». Но вместо этого я получаю "-6.27744e + 066".

Pop (), кажется, работает. Сорта. Имея реальные проблемы с push (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 "Debug\chapter 16-5.lastbuildstate".
1>InitializeBuildStatus:
1>  Creating "Debug\chapter 16-5.unsuccessfulbuild" because "AlwaysCreate" was specified.
1>ClCompile:
1>  main.cpp
1>e:\programming(cpp)\chapter 16-5\chapter 16-5\vect1.h(31): warning C4244: 'initializing' : conversion from 'double' to 'unsigned int', possible loss of data
1>          e:\programming(cpp)\chapter 16-5\chapter 16-5\vect1.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-5\chapter 16-5\main.cpp(11) : see reference to class template instantiation 'vect1<T>' being compiled
1>          with
1>          [
1>              T=double
1>          ]
1>Manifest:
1>  Deleting file "Debug\chapter 16-5.exe.embed.manifest".
1>LinkEmbedManifest:
1>  chapter 16-5.vcxproj -> E:\Programming(CPP)\chapter 16-5\Debug\chapter 16-5.exe
1>FinalizeBuildStatus:
1>  Deleting file "Debug\chapter 16-5.unsuccessfulbuild".
1>  Touching "Debug\chapter 16-5.lastbuildstate".
1>
1>Build succeeded.
1>
1>Time Elapsed 00:00:10.62
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

Ответы [ 2 ]

1 голос
/ 10 февраля 2012
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){

Вы используете константную ссылку, потому что вам, вероятно, сказали, что это быстрее, чем передавать по значению.Ну, это верно для больших объектов, а не для int.Ссылка - это просто другой указатель (с другим синтаксисом).Функция передает адрес целевой переменной.Pointer и 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.
}

и добавить деструктор, освобождающий выделенную память.

Надеюсь, это помогло, и я сожалею о своем плохом английском

0 голосов
/ 10 февраля 2012

Непосредственная проблема, которую я обнаружил, такова:

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. Классы, выделяющие память, также должны освобождать память в своем деструкторе, т. Е. Вам нужно реализовать деструктор. Так как этот тип также может быть копируемым, но созданная по умолчанию конструкция копирования и назначение копирования делают неправильно, вам также необходимо определить их.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...