Пользовательский класс string

211
29 мая 2018, 18:20

Зависает программа после ввода строки.Подскажите в чем ошибка?

#include<iostream>
#include <cstring>
class MyString
{
    private:
        size_t length;
        char *str;
    public:
        MyString ();
        MyString (const char *c);
        MyString (const MyString& t);
        ~MyString ();
        MyString& operator= (const MyString& t);
        MyString& operator= (const char *c);
        MyString operator+ (const MyString& t) const;
        MyString& operator+= (const MyString& t);
        char& operator[] (size_t i);
        const char& operator[] (size_t i) const;
        char& at (size_t i);
        const char& at (size_t i) const;
        void get_input (std::istream& in);
        size_t get_length () const;
        void from_c_str (const char *other);
        friend std::ostream& operator<< (std::ostream& out, const MyString& t);
        friend std::istream& operator>> (std::istream& in, MyString& t);
        friend bool operator== (const MyString& t, char *c);
        friend bool operator== (const MyString& t, const MyString& t1);
        friend bool operator!= (const MyString& t, char *c);
        friend bool operator!= (const MyString& t, const MyString& t1);
};
MyString::MyString ()
{
    length = 1;
    str = '\0';
}
MyString::MyString (const char *c)
{
    from_c_str (c);
}
MyString::MyString (const MyString& t)
{
    from_c_str (t.str);
}
MyString::~MyString ()
{
    delete[] str;
}
MyString& MyString::operator= (const MyString& t)
{
    from_c_str (t.str);
    return *this;
}
MyString& MyString::operator= (const char *c)
{
    from_c_str (c);
    return *this;
}
MyString MyString::operator+ (const MyString& t) const
{
    return (MyString(str) += t.str);
}




bool operator== (const MyString& t, char *c)
{
    return (strcmp(t.str, c) == 0);
}
bool operator== (const MyString& t, const MyString& t1)
{
    return (strcmp(t.str, t1.str) == 0);
}
bool operator!= (const MyString& t, char *c)
{
    return !(operator== (t, c));
}
bool operator!= (const MyString& t, const MyString& t1)
{
    return !(operator== (t, t1.str));
}
MyString& MyString::operator+= (const MyString& t)
{
    length = strlen (str) + strlen (t.str) + 1;
    char *newStr = new char[length];
    strcpy (newStr, str);
    strcat (newStr, t.str);
    strcpy (str, newStr);
    str[length-1] = '\0';
    delete[] newStr;
    return *this;
}
char& MyString::operator[] (size_t i)
{
    return str[i];
}
const char& MyString::operator[] (size_t i) const
{
    return str[i];
}
void MyString::get_input (std::istream& in)
{
    while (true)
    {
        char c = in.get ();
        if (c == '\n')
        {
            break;
        }
        if (length == 0)
        {
            length = 2;
        }
        else
        {
            ++length;
        }
        char* newStr = new char[length];
        if (str != NULL)
        {
            strcpy (newStr, str);
        }
        newStr[length-2] = c;
        newStr[length-1] = '\0';
        delete[] str;
        str = newStr;
    }
}
size_t MyString::get_length () const
{
    return (length - 1);
}
void MyString::from_c_str (const char *c)
{
    length = strlen (c) + 1;
    str = new char[length];
    strcpy (str, c);
}
std::ostream& operator<< (std::ostream& out, const MyString& t)
{
    out << t.str;
    return out;
}
std::istream& operator>> (std::istream& in, MyString& t)
{
    t.get_input (in);
    return in;
}
int main()
{
    MyString st;
    MyString zt;
    MyString tt;
    cin >> st;
    cout << st<<endl;
    cin >> zt;
    cout <<zt<<endl;
    tt = st += zt;
    cout << tt;
    system("pause");
    return 0;
}
Answer 1
  1. MyString::MyString ()
    {
      length = 1;
      str = '\0';
    }
    

    Начиная с C++11 str = '\0' уже запрещено. Да и даже до С++11 такая запись хоть и являлась корректной, но все равно была сбивающей с толку. Это эквивалентно str = nullptr. Почему при этом делается length = 1 - не ясно. Откуда взялось 1?

  2. MyString& MyString::operator+= (const MyString& t)
    {
      length = strlen (str) + strlen (t.str) + 1;
      char *newStr = new char[length];
      strcpy (newStr, str);
      strcat (newStr, t.str);
      strcpy (str, newStr);
      str[length-1] = '\0';
      delete[] newStr;
      return *this;
    }
    

    Тут уже написана какая-то чушь. Результат правильно формируется в newStr, но потом зачем-то тупо копируется в str при помощи strcpy (str, newStr) (!). Это как это? В str не хватит места для всей newStr. Вылет за пределы выделенной памяти, поведение не определено.

  3. MyString& MyString::operator= (const MyString& t)
    {
      from_c_str (t.str);
      return *this;
    }
    MyString& MyString::operator= (const char *c)
    {
      from_c_str (c);
      return *this;
    }
    

    В результате такого "присваивания" старое содержимое строки становится утечкой памяти. Оператор присваивания обязан освобождать старое содержимое строки.

  4. Оператор += написан только в одной форме

    MyString MyString::operator+ (const MyString& t) const
    

    но при этом используется в коде со вторым операндом типа char *. Это работает благодарая конструктору конверсии

    MyString::MyString (const char *c)
    

    Но почему тогда для всех остальных операторов реализовано две отдельных версии? одна для MyString, другая для const char *c? Где логика? И почему в реализации

    MyString MyString::operator+ (const MyString& t) const
    {
      return (MyString(str) += t.str);
    }
    

    делается вызов += именно с использованием конструктора конверсии, когда можно было запросто обойтись без него

    MyString MyString::operator+ (const MyString& t) const
    {
      return MyString(*this) += t;
    }
    

    ?

Answer 2

В конструкторе

MyString::MyString ()
{
    length = 1;
    str = '\0';
}

переменная str указывает на константную область кода, а в коде везде вы удаляете str последствия непредсказуемые. Сначала нужно выделять память и записывать туда нулевой байт. Ошибка в сложении двух строк :

MyString& MyString::operator+= (const MyString& t)
{
    length = strlen (str) + strlen (t.str) + 1;
    char *newStr = new char[length];
    strcpy (newStr, str);
    strcat (newStr, t.str);
    strcpy (str, newStr);
    str[length-1] = '\0';
    delete[] newStr;
    return *this;
}

Новая строка newStr уже собрана, а вы копируете большую строку в маленькую часть памяти str. Можно сделать это так :

delete[] str;
str = newStr;
READ ALSO
Процесс ест 50% ЦП- C++

Процесс ест 50% ЦП- C++

Как можно упростить/улучшить код, чтобы он не кушал ~50% ЦП? Вот, собственно, код:

183
Неизвестная проблема с boost::process C++

Неизвестная проблема с boost::process C++

возникла проблема с использованием boost, использую пример по туториалу с двуноправленным контейнером, но он почему-то отказывается работать

180
Bool true или false [закрыт]

Bool true или false [закрыт]

Мне нужно сделать bool, который будет возвращать true, если (1 + (rand() % 101)) <= 50, в противном случае возвращать false

312