为读取和写入定义operator []

use*_*983 6 c++ class operator-overloading

在"The C++ Programming Language"一书中,作者给出了以下示例以及几个语句:

如果仅仅返回引用并让用户决定如何处理它是不可接受的,那么定义用于读取和写入的操作符(例如[])是很困难的.

Cref,是帮助实现区分阅读和写作的下标操作符.

为什么[]难以定义何时用于读写?类Cref的定义如何帮助解决这个问题?

  class String{
     struct Srep; 
     Srep *rep; 

     public: 
        class Cref;

     // some definitions here
     void check (int i) const { if (i<0 || rep->sz<=i) throw Range( );}

     char read( int i) const {return rep->s[i];}
     void write(int i, char c){ rep=rep->get_own_copy(); rep->s[i]=c;}

     Cref operator[] (int i){ check(i); return Cref(*this, i);}
     char operator[] (int i) const{check(i); return rep->s{i];}

   }

  class String::Cref{
    friend class String;
          String& s;
          int i;
          Cref(String& ss, int ii): s(ss),i(ii) {}
    public:
          operator char( ) { return s.read(i);}
          void operator=(char c){s.write(i,c);}
  };
Run Code Online (Sandbox Code Playgroud)

Ken*_*oom 8

如果您没有定义Cref解决此问题的类,那么您必须执行以下std::map操作:

template class <K,V> class map{
   V& operator[](K const & key);
}
Run Code Online (Sandbox Code Playgroud)

这将返回一个引用,该引用必须由有效的内存位置支持,因此

std::map<string,string> m;
m["foo"];
assert(m.find("foo") != m.end());
Run Code Online (Sandbox Code Playgroud)

断言将成功(意思"foo"是,现在是地图中的有效键),即使您从未分配过某些内容m["foo"].

这种违反直觉的行为可以通过Cref示例中的类来修复- 它可以执行适当的逻辑,m["foo"]仅在分配给引用时创建,并确保m.find("foo") == m.end()在尝试读取不存在时不执行某些赋值m["foo"].

同样,在您的String类中(这是一个引用计数字符串 - 字符串共享其字符串数据,并且当您更改其数据与另一个字符串共享的字符串时创建新副本),您必须在复制时通过operator[]阅读文字.使用Cref该类,可以确保您在使用时只进行复制operator[].

  • `Cref` 方法的一个缺点是用于类型推断的新 `auto` 关键字,在 `auto c=mystring[5]` 中现在将具有错误的类型。 (2认同)