定义读写操作符 [ ]

发布于 2024-10-21 08:27:20 字数 991 浏览 1 评论 0原文

在《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);}
  };

In the book of "The C++ Programming Language", the author gave the following example along with several statements:

Defining an operator, such as [], to be used for both reading and writing is difficult where it is not acceptable simply to return a reference and let the user decide what to do with it.

Cref, is to help implement a subscript operator that distinguishes between reading and writing.

Why [] is difficult to be defined when to be used for both reading and writing?
How does the definition of class Cref help to solve this issue?

  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);}
  };

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ヤ经典坏疍 2024-10-28 08:27:20

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

template class <K,V> class map{
   V& operator[](K const & key);
}

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

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

断言将会成功(意味着 "foo" 现在是映射中的有效键),即使您从未将某些内容分配给 m["foo"].

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

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

If you don't define a class Cref that solves this issue, then you have to do what std::map does:

template class <K,V> class map{
   V& operator[](K const & key);
}

This returns a reference, which must be backed by a valid memory location, and therefore

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

The assertion will succeed (meaning, "foo" is now a valid key in the map) even though you never assigned something to m["foo"].

This counterintuitive behavior can be fixed by the Cref class in your example -- it can perform the appropriate logic to create m["foo"] only when you assign to the reference, and ensure that m.find("foo") == m.end() if you didn't perform some assignment when you tried to read the nonexistant m["foo"].

Likewise, in your String class (which is a reference-counted string -- strings share their string data, and a new copy is created when you change a string whose data is shared with another string), you'd have to make a copy when using operator[] to read characters. The use of the Cref class, allows you to ensure that you only make a copy when using operator[] to write.

回忆凄美了谁 2024-10-28 08:27:20
String s;
s[0] = 5;

将调用 String::operator [](int),然后调用 String::Cref::operator =(char)

但是,

String s;
char c = s[0];

将调用 String::operator [](int),然后调用 String::Cref::operator char()

读取时,String::Cref::operator char 被调用,而写入时,String::Cref::operator = 被调用 - 这允许您区分读取和读取写作。

String s;
s[0] = 5;

will call String::operator [](int) and then String::Cref::operator =(char).

However,

String s;
char c = s[0];

will call String::operator [](int) and then String::Cref::operator char().

When reading, String::Cref::operator char is called, and when writing String::Cref::operator = is called - this allows you to distinguish between reading and writing.

别靠近我心 2024-10-28 08:27:20

为什么 [] 很难被定义何时用于两者 区分阅读和写作?


这是因为每当您有一个非常量对象时,即使您以只读方式使用它,也会调用非常量 operator[]

Why [] is difficult to be defined when to be used for both distinguish between reading and writing?

It's because the non-const operator[] is called whenever you have a non-const object, even if you're using it in a read-only fashion.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文