оператор, изменяющий аргумент класса без причины (* int) - PullRequest
2 голосов
/ 26 ноября 2011

В моем файле класса я имею:

class File
{
    std::vector<char> name, timeOfCreation, timeOfLastEdit, content;
    std::vector<char>::const_iterator* pPos, *pPosOfEnd;
    int *pSize;
    bool *pForcedSize;
    void setTimeOfLastEdit();
    int* indexOfLastChar, *indexOfCurrentChar;

    friend class Interface;
    friend class Directory;
public:
    File(std::string, int argSize = 0, std::string arg_content = 0); // constructor
    File(); // constructor
    File(const File&); // copy constructor
    ~File(); // destructor
    char* returnName(); 

    File& operator = (const File&);
    File operator += (const int);
    File operator -= (const int);
    File& operator ++ (); // prefix
    File& operator -- (); // prefix
    File operator ++ (int); // postfix
    File operator -- (int); // postfix

    bool operator ! ();

    int operator () (char*, int);

    friend  bool operator == (const File&, const File&);
    friend  bool operator != (const File&, const File&);
    friend  bool operator >= (const File&, const File&);
    friend  bool operator <= (const File&, const File&);
    friend  bool operator < (const File&, const File&);
    friend  bool operator > (const File&, const File&);

    friend std::istream & operator >> (std::istream&, File&);
    friend std::ostream & operator << (std::ostream&, File);

};

, и мой оператор () выглядит так:

int File::operator () (char* contentNextNBytes, int n)
{
    int i; int j = 0;
    std::vector<char>::const_iterator it = content.begin();
    for(j = 0; j < *indexOfCurrentChar; j++)
        ++it;

    for(i = 0; i < n; i++)
    {
        contentNextNBytes[i] = *it;
        if(i == *indexOfLastChar-1) 
        {
            contentNextNBytes[i+1] = '\0';
            *indexOfCurrentChar = i+1;
            return i+1;
        }
        ++it;
    }

    contentNextNBytes[i] = '\0';
    *indexOfCurrentChar = n;
    return n;
}

В моем другом классе, Интерфейс, я вызываю оператора() с int i = dir[index](buffer, n), где n - это число байтов, а index - это индекс файла в каталоге.

Теперь, как это реализовано в операторе, значение * indexOfCurrentChar, на которое указывает (должен ли) стать позиция последнего символа, извлеченного из файла.Однако, когда я снова вызываю тот же оператор для того же индекса с int j = dir[index](buffer, n1), то сразу, когда программа вводит оператор {}, она снова меняет значение * indexOfCurrentChar на 0, в то время как мой код должен продолжаться с последнего символа и читатьследующие n1 байтов в файле

Почему это происходит?: (

Вот часть кода, которую я использую для вызова оператора в классе Interface:

 buffer = new char[n+1];
    k = d[index](buffer, n);
    std::cout<<"Extracting of "<<k<<" bytes succeeded, and here is the content extracted:\n";
std::cout<<"\""<<buffer<<"\"";

Edit1: Здесь я изменяю свой indexOfCurrentChar:

1) В операторе присваивания = (однако я не вызываю его в своем классе Interface) 2) В конструкторе копирования (также не использующем его в классе Interface, и он просто копирует значение) 3) В конструкторе File:

File::File()
{
    // stuff
    indexOfCurrentChar = new int;
} //I'm not setting its value, just allocating memory

4) В конструкторе файла:

File::File(std::string arg_name, int arg_size, std::string arg_content)
{
     // stuff
     indexOfCurrentChar = new int;
     *indexOfCurrentChar = 0;
    //setting it to 0, but its just at creation time
}

5) В операторе >> // получение содержимого файла

std::cout<<"Enter file content: ";
    *object.indexOfCurrentChar = 0;
    while( in.get(c) && c != '\n');
    i = 0;
    in.get(c);
    if(*(object.pSize) == 0)
    {
        while(c != '\n')
        {
            object.content.push_back(c);
            in.get(c);  
            ++i;
        }
        *(object.pSize) = (int)object.content.size();
        *(object.pPosOfEnd) = object.content.end();
        *object.indexOfLastChar = i;
    }
    else
    {
        i = 0;
        std::vector<char>::const_iterator it = object.content.begin();
        while(c != '\n')
        {
            if(i == *object.pSize)
            {
                *object.pPosOfEnd = it;
                *object.indexOfLastChar = i;
            }
            if(i >= *object.pSize)
            {
                in.get(c);
                continue;
            }
            object.content.push_back(c);
            in.get(c);
            ++i;
        }
    }


    *(object.pPos) = object.content.begin();

И вот оно:)

А-а-а, и мне жаль показывать это миру, вот мой уродливый метод класса Interface.Все мои программы ввода / вывода управляются с помощью метода Interface.writeOutput, который находится здесь:

Interface::Interface()
{
    menu = new char*[12];
    menu[0] = "Welcome, please select an option from the following, by pressing the respective numbers:";
    menu[1] = "1  Create a Directory\n2  Create a single File\n3  Exit program";
    menu[2] = "Ok, now please select a further option:";
    menu[3] = "Enter the number of Files you want to import: ";
    menu[4] = "Enter the files...";
    menu[5] = "1  Write out the Directory details\n2  Extract N bytes from a desired file\n3  Remove a file with desired name from the Directory\n4  Write content of a file\n0  Go back to the beginning";
    menu[6] = "Enter the index of the file: ";
    menu[7] = "Enter how many bytes to extract: ";
    menu[8] = "Content of the extracted bytes: ";
    menu[9] = "Enter the name of the file: ";
    menu[10] = "What do you want to do next?";
    menu[11] = "Please enter a regular number...";
}


void Interface::writeMenu()
{
    Error e;
    char c, tmp[5], name[30];
    int n, k, index, i, numDir;
    char *buffer; 
    int *haveReadFiles;

    std::cout<<menu[0];
    std::cout<<"\n\n";
startMenu: 
    std::cout<<menu[1];
    std::cout<<"\n\n";
    std::cin>>c;
    if((!isdigit(c)) || ( c != '1' && c!= '2' && c!='3'))
    {
        std::cout<<"\n"<<menu[11]<<"\n\n";
        goto startMenu;
    }
    if(c == '1')
    {
        std::cout<<"Enter the name of the directory: ";
        std::cin>>name;
        Directory d(name);
        std::cout<<"\n\n\nEnter number of files of directory: ";
        std::cin>>numDir;
        haveReadFiles = new int[numDir];
        if(!haveReadFiles)
        {
            e.writeToOutput(7);
            exit(1);
        }

        for(i = 0; i < numDir; i++)
        {
        haveReadFiles[i] = 0;   
            //std::cin.ignore(5,'\n');
        //  std::cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
            File f;
            std::cin>>f;
            d += f;
        }

    menu1:
        std::cout<<"\n\n"<<menu[2]<<"\n\n";
menuRepeat:
        std::cout<<menu[5];
        std::cout<<"\n\n";
        std::cin>>c;
        if(!isdigit(c) || (c != '1' && c!= '2' && c!='3' && c != '4' && c != '0'))
        {
            std::cout<<"\n"<<menu[11];
            goto menu1;
        }
        switch(c)
        {
        case '0': goto startMenu;break;
        case '1': std::cout<<d;break;
        case '2': 
            {
                menu2:
                std::cout<<"\n\n"<<menu[6];

                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menu2;
                    }
                index = atoi(tmp);
                menu3:
                std::cout<<"\n\n"<<menu[7];
                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menu3;     
                    }
                n = atoi(tmp);


                buffer = new char[n+1];
                k = d[index](buffer, n);
                std::cout<<"Extracting of "<<k<<" bytes succeeded, and here is the content extracted:\n";
                std::cout<<"\""<<buffer<<"\"";
            } break;
        case '3':
            {
                std::cout<<"\n\nEnter the name of the file: ";
                std::cin>>name;
                d -= name;
                std::cout<<"...file removed!\n";
                std::cout<<"Directory without the removed file looks like this: \n\n"<<d;
            }break;
        case '4': 
            {
                menuFF:
                std::cout<<"\n\nEnter the index of the desired file: ";
                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menuFF;
                    }
                index = atoi(tmp);
                std::cout<<"\nHere's the content:\n";
                File ff = d[index];
                std::vector<char>::const_iterator iter = ff.content.begin();
                for(; iter < ff.content.end(); ++iter)
                {
                    std::cout<<*iter;
                }
                std::cout<<"\n\n";
            }
        }
        menu4:
        std::cout<<"\n\nWhat do you want to do now?\n\n1  Exit program\n2  Go back to start menu\n3  Do more stuff with your Directory\n\n";
        std::cin>>c;
        if((!isdigit(c)) || ( c != '1' && c!= '2' && c!='3'))
        {
            std::cout<<"\n"<<menu[11];
            goto menu4;
        }
        if(c=='1')
        {
            "Thank you, goodbye...";
            exit(0);
        }
        if(c=='2')
            goto startMenu;
        if(c=='3')
            goto menuRepeat;
    }
    else if(c=='2')
    {
        std::cout<<"Enter your file...\n";
        File g;
        std::cin>>g;
        menuZZ:
        std::cout<<"\n\nHere's what you can do with your file: \n\n1  Extract N bytes of content from it\n2  Write its content out\n3  Write its properties out\n4  Return to start menu\n\n";
        std::cin>>c;
        switch(c)
        {
        case '1':
            {

                menuYY:
                std::cout<<"\n\n"<<menu[7];
                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menuYY;        
                    }
                n = atoi(tmp);
                buffer = new char[n+1];
                k = g(buffer, n);
                std::cout<<"Extracting of "<<k<<" bytes succeeded, and here is the content extracted:\n";
                std::cout<<"\""<<buffer<<"\"";
                std::cout<<"\n\n";
                goto startMenu;
            } break;
        case'2':
            {
                std::vector<char>::const_iterator it = g.content.begin();
                for(; it < g.content.end(); ++it)
                {
                    std::cout<<*it;
                }
                std::cout<<"\n\n";
            }
        case'3':
            {
                std::cout<<g<<"\n\n";
                goto startMenu;
            } break;
        case'4': 
            {
                std::cout<<"\n\n";
                goto startMenu;
            } break;
        default:
            {
                std::cout<<menu[11];
                goto menuZZ;    
            }

        }
    }
    else
    {
        std::cout<<"Thank you, goodbye... ";
        exit(0);
    }
}

Редактировать 2:

И последнее, но не менее важное: Directory::operator [] implementation:

В шапке: File& operator [] (int);

Реализация:

 File& Directory::operator [] (int index)
{
    std::vector<File>::const_iterator i = arr.begin();
    for(int j = 0; j < index; ++j)
        ++i;
    File* temp = new File;
    *temp = *i;
    return *temp;
    delete temp;
}

Наслаждаться ^^

Ответы [ 3 ]

2 голосов
/ 26 ноября 2011

Я предполагаю, что проблема в классе Directory и способе, которым он хранит и возвращает File объекты.Например, если Directory::operator[] возвращает File вместо File &, то любые изменения, внесенные в возвращенный объект, не будут сохранены во внутренней его копии Directory, поэтому два вызова подряднапример

int i = dir[index](buffer, n);
int j = dir[index](buffer, n1);

фактически вызывает File::operator() для двух разных временных File объектов.Это может объяснить, почему значение *indexOfCurrentChar не соответствует ожидаемому.

EDIT

Теперь, когда вы продемонстрировали реализацию Directory::operator[], я могууверенно говорю, что мои подозрения были верны.Даже если вы изменили сигнатуру Directory::operator[], чтобы она теперь возвращала File &, ваша реализация по-прежнему будет вести себя не так, как вы хотите, потому что она не возвращает ссылку на правильный объект File (Directory внутренняя копия объекта).Три оператора

File* temp = new File;
*temp = *i;
return *temp;

создают новую копию внутреннего File объекта Directory объекта и возвращают ссылку на него, поэтому любые изменения, внесенные в возвращаемые переменные-члены возвращаемого объекта File, не являютсяотражено в соответствующей записи вектора Directory::arr.Так как vector::operator[] возвращает ссылку, изменение тела Directory::operator[] на просто

return arr[index];

должно дать вам желаемое поведение.

Я должен также отметить, что ваша текущая реализация Directory::operator[] утечка памяти: delete temp; никогда не запускается, потому что return *temp; заставляет элемент управления выйти из функции.

0 голосов
/ 26 ноября 2011

Я разместил это как комментарий, но я думаю,

indexOfCurrentChar = n; 

должно быть

 *indexOfCurrentChar += n; 
0 голосов
/ 26 ноября 2011

Я бы рекомендовал заменить

 if(i == *indexOfLastChar-1)

с

 if(i == (*indexOfLastChar)-1)

Я думаю, что вы читаете значение до 'indexOfLastChar' и сравниваете это с i.

...