Бьерн Страуструп - Язык программирования С++. Главы 5-8
Страница 66. Строковый класс



7.11 Строковый класс

 Теперь можно привести более осмысленный вариант класса string.
 В нем подсчитывается число ссылок на строку, чтобы минимизировать
 копирование, и используются как константы стандартные строки C++.

            #include <iostream.h>
            #include <string.h>

            class string {
               struct srep {
                 char* s;       // указатель на строку
                 int n;         // счетчик числа ссылок
                 srep() { n = 1; }
               };
               srep *p;

            public:
              string(const char *);   // string x = "abc"
              string();               // string x;
              string(const string &); // string x = string ...
              string& operator=(const char *);
              string& operator=(const string &);
              ~string();
              char& operator[](int i);

              friend ostream& operator<<(ostream&, const string&);
              friend istream& operator>>(istream&, string&);

              friend int operator==(const string &x, const char *s)
                { return strcmp(x.p->s,s) == 0; }

              friend int operator==(const string &x, const string &y)
                { return strcmp(x.p->s,y.p->s) == 0; }

              friend int operator!=(const string &x, const char *s)
                { return strcmp(x.p->s,s) != 0; }

              friend int operator!=(const string &x, const string &y)
                { return strcmp(x.p->s,y.p->s) != 0; }
           };

Конструкторы и деструкторы тривиальны:

           string::string()
           {
             p = new srep;
             p->s = 0;
           }

           string::string(const string& x)
           {
             x.p->n++;
             p = x.p;
           }

           string::string(const char* s)
           {
             p = new srep;
             p->s = new char[ strlen(s)+1 ];
             strcpy(p->s, s);
           }

           string::~string()
           {
             if (--p->n == 0) {
                delete[]  p->s;
                delete p;
             }
           }

 Как и всегда операции присваивания похожи на конструкторы. В них
 нужно позаботиться об удалении первого операнда, задающего левую
 часть присваивания:

          string& string::operator=(const char* s)
          {
            if (p->n > 1) {  // отсоединяемся от старой строки
                p->n--;
                p = new srep;
            }
            else    // освобождаем строку со старым значением
                delete[] p->s;

            p->s = new char[ strlen(s)+1 ];
            strcpy(p->s, s);
            return *this;
          }

          string& string::operator=(const string& x)
          {
            x.p->n++;  // защита от случая ``st = st''
            if (--p->n == 0) {
               delete[] p->s;
               delete p
            }
            p = x.p;
            return *this;
          }

 Операция вывода показывает как используется счетчик числа ссылок.
 Она сопровождает как эхо каждую введенную строку (ввод происходит
 с помощью операции << , приведенной ниже):

          ostream& operator<<(ostream& s, const string& x)
          {
             return s << x.p->s << " [" << x.p->n << "]\n";
          }

 Операция ввода происходит с помощью стандартной функции ввода
 символьной строки ($$10.3.1):

          istream& operator>>(istream& s, string& x)
          {
             char buf[256];
             s >> buf;   // ненадежно: возможно переполнение buf
                         // правильное решение см. в $$10.3.1
             x = buf;
             cout << "echo: " << x << '\n';
             return s;
           }

      Операция индексации нужна для доступа к отдельным символам.
 Индекс контролируется:

          void error(const char* p)
          {
            cerr << p << '\n';
            exit(1);
          }

         char& string::operator[](int i)
        {
         if (i<0 || strlen(p->s)<i) error("недопустимое значение индекса");
           return p->s[i];
        }

    В основной программе просто даны несколько примеров применения
 строковых операций. Слова из входного потока читаются в строки,
 а затем строки печатаются. Это продолжается до тех пор, пока не
 будет обнаружена строка done, или закончатся строки для записи
 слов, или закончится входной поток. Затем печатаются все строки
 в обратном порядке и программа завершается.

         int main()
         {
           string x[100];
           int n;

           cout << " здесь начало \n";

           for ( n = 0; cin>>x[n]; n++) {
               if (n==100) {
                  error("слишком много слов");
                  return 99;
               }
               string y;
               cout << (y = x[n]);
               if (y == "done") break;

           }
           cout << "теперь мы идем по словам в обратном порядке \n";
           for (int i=n-1; 0<=i; i--) cout << x[i];
           return 0;
         }

 
« Предыдущая статья   Следующая статья »