2012-02-17 3 views
1

Для обучения я пытаюсь написать класс типа std :: string. Я прочитал, что метод at (int) возвращает ссылку на символ и выдает исключение в случае неверного индекса (слишком длинного или отрицательного). Оператор [] вместо этого не вызывает никаких исключений. Но так как он возвращает ссылку, если индекс слишком длинный, что он возвращает? Это класс у меня есть:Доступ к строковому классу с помощью оператора []

class string 
{ 
    public: 
    static const unsigned int length_max=100; 
    string(const char* field=NULL) 
    { 
     if(field!=NULL) 
     { 
      const unsigned int length=strlen(field); 
      this->field=new char[length+1]; 
      this->length=length; 
      for(unsigned int i=0;i<=length;i++) 
       this->field[i]=field[i]; 
     } 
     else 
     { 
      this->field=NULL; 
      length=0; 
     } 
    } 
    string& operator=(const char* field) 
    { 
     const unsigned int length=strlen(field); 
     if(this->field!=NULL) 
      delete this->field; 
     this->field=new char[length]; 
     this->length=length; 
     for(unsigned int i=0;i<length;i++) 
      this->field[i]=field[i]; 
     return *this; 
    } 
    string& operator= (const string& str) 
    { 
     *this=str.field; 
     return *this; 
    } 
    operator char*() 
    { 
     return field; 
    } 
    friend std::ostream& operator<< (std::ostream& out, string& str); 
    friend std::istream& operator>> (std::istream& in, string& str); 
    private: 
    char* field; 
    unsigned int length; 
}; 

std::ostream& operator<<(std::ostream& out, string& str) 
{ 
    out << str.field; 
    return out; 
} 

std::istream& operator>> (std::istream& in, string& str) 
{ 
    char temp[string::length_max]; 
    in >> temp; 
    str=temp; 
    return in; 
} 

Я хочу, чтобы оператор [], я также мог бы сделать это выбросить исключение, но проблема в том, что я не знаю, что должен это вернуть в случае индекс слишком длинный. Например, оператор [] перегрузка это:

char& operator[] (int i) 
    { 
     try 
     { 
      if(i<0 || i>=length) 
       throw indexException(); 
      return field[i]; 
     } 
     catch(indexException& e) 
     { 
      std::cerr << e.what() << std::endl; 
     } 
    } 

Это исключение:

class indexException:std::exception 
{ 
    public: 
    virtual const char* what() 
    { 
     return "Index is either too long, or negative"; 
    } 
}; 

Он должен возвращать ссылку обугленной и не только символ, потому что я хочу, чтобы сделать его переуступку, поэтому, например, если у меня есть строка str, я могу сказать str [5] = 'c'. Я также хочу обработать исключение и не покидать программу с помощью exit(). Так что если есть исключение, оно не возвращает никакого значения, строка также может быть пустой. Что мне вернуть? Я бы сделал его похожим на std :: string, но я не очень хорошо понял, как реализуется одна из std :: string.

+1

Почему вы ловите исключение внутри 'operator []'? Пусть он убежит к пользователю и позволит им его поймать; бросать и ловить в одном месте не имеет никакой цели. – ildjarn

+0

undefined behavior – PlasmaHH

ответ

2

Нет смысла бросать исключение, если вы собираетесь поймать его в том же блоке. Просто выполните инструкцию if, если вы хотите что-то вернуть, а не бросать ошибку вне вашей функции.

Стандартный класс строк не выполняет никакой проверки в своем индексе, так что нет дополнительных накладных расходов. Если индекс за пределами границ, вы получаете неопределенное поведение, потому что вы используете индекс вне границ во внутреннем буфере.

Вы можете выбрать все, что хотите вернуть за пределы индексов. Нуль был бы хорошим выбором, так как это означало бы конец строки в стиле C.

+0

Я мог бы вернуть ноль, но он возвращает ссылку. Так что мне делать, выделить новый символ и установить его на ноль? –

+0

Если вам нужна проверка границ, просто выбросьте исключение. – rasmus

+0

@Ramy: Возвращение часового 'char &' (в отличие от 'char const &') не реально выполнимо. ИМО, вам гораздо лучше идти на маршруты UB или исключения. – ildjarn

Смежные вопросы