const修饰的operator[]为什么可以修改字符串,怎么做越界处理比较好

#include <iostream>                                                                        
#include <cstring> 

using namespace std;

class String {
    char *ptrChars;

public:
    String(char const *chars);

    String & operator=(String const &); 
    String & operator=(char const *); 

    char & operator[](const size_t index) const noexecpt(false);

    void print() const;
};

String::String(char const *chars) {
    chars = chars ? chars : ""; 
    ptrChars = new char[strlen(chars) + 1]; 
    strcpy(ptrChars, chars);
}

String & String::operator=(String const &str) {
    if (strlen(ptrChars) != strlen(str.ptrChars)) {
        char *ptrHold = new char[strlen(str.ptrChars) + 1]; 
        delete[] ptrChars;
        ptrChars = ptrHold;
    }   
    strcpy(ptrChars, str.ptrChars);

    return *this;
}

String & String::operator=(char const *ptr) {
    if (strlen(ptrChars) != strlen(ptr)) {
        char *ptrHold = new char[strlen(ptr) + 1]; 
        delete[] ptrChars;
        ptrChars = ptrHold;
    }   
    strcpy(ptrChars, ptr);

    return *this;
}

char & String::operator[](const size_t index) const noexcept(false) {
    /* throw "out of range"; */
        return ptrChars[index];
}

void String::print() const {
    cout << ptrChars << endl;
}

int main()
{
    s = "Cat";
    s.print();
    s[0] = 'a'; // 为什么可以
    s.print();
        cout << s[10] << endl; // 怎么做越界处理
    return 0;
}

关于,operator= 这个函数有两个问题

  1. 怎么做越界处理比较好, throw就直接退出来了,有没有就是给出提示然后接着运行的
  2. 加了const了,为什么还能修改s[0] = a

https://blog.csdn.net/weixin_39743893/article/details/81076355