MoreEffectiveC++
1.1. μκ° ¶
Reference counting(μ΄ν μ°Έμ‘° μΈκΈ°, λ¨μ΄κ° κΈΈμ΄ μμ΄ νΌμ© νμ§ μμ)λ κ°μ κ°μΌλ‘ ννλλ μλ§μ κ°μ²΄λ€μ νλμ κ°μΌλ‘ 곡μ ν΄μ νννλ κΈ°μ μ΄λ€. μ°Έμ‘° μΈκΈ°λ λκ°μ§μ μΌλ°μ μΈ λκΈ°λ‘ μ μλμλλ°, 첫λ²μ§Έλ‘ heap κ°μ²΄λ€μ μμ©νκΈ° μν κΈ°λ‘μ λ¨μνλ₯Ό μν΄μ μ΄λ€. νλμ κ°μ²΄κ° λ§λ€μ΄ μ§λλ°, newκ° νΈμΆλκ³ μ΄κ²μ deleteκ° λΆλ¦¬κΈ° μ κΉμ§ λ©λͺ¨λ¦¬λ₯Ό μ°¨μ§νλ€. μ°Έμ‘° μΈκΈ°λ κ°μ μλ£λ€μ μ€λ³΅λ κ°μ²΄λ€μ νλλ‘ κ³΅μ νμ¬, newμ deleteλ₯Ό νΈμΆνλ μ€νΈλ μ€λ₯Ό μ€μ΄κ³ , λ©λͺ¨λ¦¬μ κ°μ²΄κ° λ±λ‘λμ΄ μ μ§λλ λΉμ©λ μ€μΌμ μλ€. λλ²μ§Έμ λκΈ°λ κ·Έλ₯ μΌλ°μ μΈ μκ°μμ λμλ€. μ€λ³΅λ μλ£λ₯Ό μ¬λ¬ κ°μ²΄κ° 곡μ νμ¬, λΉμ© μ μ½ λΏμλλΌ, μμ±, νκ΄΄μ κ³Όμ μ μλ΅μΌλ‘ νλ‘κ·Έλ¨ μν μλκΉμ§ λμ΄κ³ μ νλ λͺ©μ μ΄λ€.
μ΄λ° κ°λ¨ν μκ°λ€μ μ μ©μ μν΄μλ λ§μ΄ μ°μ΄λ μλ£ννλ₯Ό μ°Ύμ μμ μΌμ 보μ¬μ£Όλ κ²μ΄ μ΄ν΄μ λμμ΄ λ리κ²μ΄λ€. μ΄λ° λ©΄μμ λ€μμ μλ μ ν©ν κ²μ΄λ€.
a~eκΉμ§ λͺ¨λ "Hello"λΌλ κ°μ κ°μ κ°μ§κ³ μλ λ€λ₯Έ κ°μ²΄μ΄λ€. μ΄ ν΄λμ€λ μ°Έμ‘° μΈκΈ°κ° μ μ©λμ§ μμκΈ° λλ¬Έμ λͺ¨λ κ°κ°μ κ°μ κ°μ§κ³ μλ€. λ¬Έμμ΄μ ν λΉ(assignment) μ°μ°μλ μλ§ λ€μκ³Ό κ°μ΄ ꡬνλμ΄ μμ κ²μ΄λ€.
μ΄ μ½λμ μλ―Έλ₯Ό κ·Έλ¦ΌμΌλ‘ νννλ©΄ λ€μκ³Ό κ°λ€.
~cpp class String { // νμ€ λ¬Έμμ΄ νμ μ΄λ² μμ΄ν μ μ°Έμ‘°μΈκΈ°λ₯Ό κ°μΆκ³ public: // μμν μ§λ§, κ·Έκ²μ λ°°μ νλ€κ³ κ°μ νμ String(const char *value = ""); String& operator=(const String& rhs); ... private: char *data; }; String a, b, c, d, e; a = b = c = d = e = "Hello";
~cpp String& String::operator=(const String& rhs) { if (this == &rhs) return *this; // Item E17 μ°Έκ³ delete [] data; data = new char[strlen(rhs.data) + 1]; strcpy(data, rhs.data); return *this; // Item E15 μ°Έκ³ }
μ΄λ¬ν κ·Έλ¦Όμ μ°Έμ‘° μΈκΈ°μμ λ§νλ μ€λ³΅ κ°μ²΄μ λν μλ£μ 곡μ λ₯Ό μ μ©μν¨ κ·Έλ¦Όμ λ€μκ³Ό κ°μ κ²μ΄λ€.
"Hello"λΌλ κ°μ νλλ§ μ μ₯λμ΄ μλ κ²μ΄κ³ , μ΄λ₯Ό λ¬Έμμ΄λ€μ΄ 곡μ ν΄μ ννμ κ°μ§κ³ μλ κ²μ΄λ€. νμ§λ§ μ€μ§μ μΌλ‘ "Hello"μ ν λΉ μμ μ μμ½κ² μμ μμ§λ§, νκ΄΄ μμ μ μμ μλκ²μ λ§λ§μΉ μλ€. κ·Έλμ νκ΄΄ μμ μ μκΈ° μν΄μ "Hello" κ°μ κ·Έκ²μ μ°Έμ‘°νλ μ λλ₯Ό κΈ°λ‘νκ³ , κ·Έ μ°Έμ‘°κ° 0κ° λλ μμ μ κ°μ νκ΄΄ μμ μΌλ‘ μΌμμΌ νλλ°, μ΄λ° μκ°μ μκΉ κ·Έλ¦Όμ λ€μ λ£μΌλ©΄ λ€μκ³Ό κ°λ€.
κ·Έλ¦¬κ³ μ¬κΈ°μ 5μ ν΄λΉ νλ μ«μλ₯Ό Reference count λΌκ³ λΆλ₯Έλ€. νΉμλ use countλΌκ³ λΆλ₯΄κΈ°λ νλλ°, νμ μ©μ΄μ λΉνμ λ°λ₯Έκ±°λ λ³ μκ΄ μνλ€. νμ§λ§ λ(scott mayer) κ·Έλ κ² μλΆλ₯Έλ€.
1.2. Implementing Reference Counting : μ°Έμ‘° μΈκΈ° μ μ© ¶
μ°Έμ‘° μΈκΈ°λ₯Ό νλ String ν΄λμ€λ₯Ό λ§λλ건 μ΄λ ΅μ§λ μμ§λ§, μΈμΈν λΆλΆμ μ£Όλͺ©ν΄μ μ΄λ»κ² κ·Έλ¬ν ν΄λμ€κ° ꡬνλλμ§ μ£Όλͺ©ν΄ 보μ. μΌλ¨, μλ£λ₯Ό μ μ₯νλ μ μ₯μκ° μκ³ , μ°Έμ‘°λ₯Ό μ
μ μλ μΉ΄μ΄ν°κ° μμ΄μΌ νλλ°, μ΄ λμ νλλ‘ λ¬Άμ΄μ StringValue κ΅¬μ‘°μ²΄λ‘ μ‘λλ€. ꡬ쑰체λ Stringμ μ¬μ(private)μ μμΉνλ€.
μ§κΈκΉμ§ λ§ν μ¬νμ κΈ°λ³Έμ λ€μκ³Ό κ°λ€.
λ¬Όλ‘ μ΄μ μ΄λ¦μ Stringκ³Ό λ€λ₯Έ μ΄λ¦μ λ§€κ²¨μΌ νκ² μ§λ§,(μλ§ RCStringμ λ?) νμ§λ§ Stringμ체λ₯Ό ꡬννλ€λ μλ―Έλ‘ κ·Έλ₯ μ΄λ¦μ μ μ§νκ³ , μμΌλ‘ λ§ν μ°Έμ‘°μΈκΈ°λ₯Ό μ μ©μν¨ String κ°μ²΄λ₯Ό λ§λ€μ΄ λκ°κ² λ€.
μ§κΈκΉμ§ λ§ν μ¬νμ κΈ°λ³Έμ λ€μκ³Ό κ°λ€.
~cpp class String { public: ... // String memberλ€ μμΉ private: struct StringValue { ... }; // μ°Έμ‘°λ₯Ό μΈλ μΈμμ, Stringμ κ°μ μ μ₯. StringValue *value; // μμ ꡬ쑰체μ κ° };
μμ κΈ°λ³Έ λμμΈμ ꡬνν΄ λ³Έλ€.
μ΄κ²μΌλ‘ StringValueμ ꡬνμ μΌλ¨ λμ΄λ€. μ΄λ₯Ό μ¬μ©νλ String κ°μ²΄μ ꡬνμ λ€μ΄κ°μΌ νλ€.
~cpp class String { private: struct StringValue { int refCount; // μ°Έμ‘°λ₯Ό μΈκΈ°μν¨ μΉ΄μ΄ν° char *data; // κ° ν¬μΈν° StringValue(const char *initValue); ~StringValue(); }; ... }; // StringValueμ λ³΅μ¬ μμ±μ, μ΄κΈ°ν λͺ©λ‘μΌλ‘ refCount μΈμ 1λ‘ μ΄κΈ°ν String::StringValue::StringValue(const char *initValue): refCount(1) { data = new char[strlen(initValue) + 1]; // μλ‘μ΄ κ° ν λΉ(μμ§ μ°Έμ‘°μΈκΈ° μ μ© x strcpy(data, initValue); // μ€νΈλ§ λ³΅μ¬ } // StringValueμ νκ΄΄μ String::StringValue::~StringValue() { delete [] data; // μ€νΈλ§ μμ }
λ¨Όμ μμ±μλ₯Ό ꡬννλ€.
ν΄λΌμ΄μΈνΈμ μ½λλ λ³΄ν΅ λ€μκ³Ό κ°λ€.
μ΄λ₯Ό μ²μ μ°Έμ‘°μΈκΈ° μ€λͺ
μ λμ¨ κ·Έλ¦ΌμμΌλ‘ μ€λͺ
νμλ©΄ λ€μκ³Ό κ°λ€.
~cpp class String { public: String(const char *initValue = ""); String(const String& rhs); ... };
~cpp // Stringμ λ³΅μ¬ μμ±μ, μ΄κΈ°ν λͺ©λ‘μΌλ‘ StringValueμ κ°μ ν λΉνλ€. String::String(const char *initValue): value(new StringValue(initValue)) {}
~cpp String s("More Effective C++");
κ·ΈλΌ Stringκ°μ²΄μ μμ±μ μλ‘ κ³΅μ νμ§ μμ λ°μ΄ν° ꡬ쑰λ₯Ό κ°μ§λλ‘ ν΄λΌμ΄μΈνΈκ° μ½λλ₯Ό μμ±νλ©΄ λ€μκ³Ό κ°λ€.
μ΄λ κ² λλλ°, μ΄λ κ·Έλ¦ΌμΌλ‘ νννλ©΄,
~cpp String s1("More Effective C++"); String s2("More Effective C++");
λ€μκ³Ό κ°λ€. μ¬κΈ°μμ "More Effective C++" λΌλ λ¬Έμμ΄μ 곡μ νλ€λ©΄, μ°Έμ‘°μΈκΈ°κ° μ΄λ£¨μ΄ μ§λ κ²μΌ κ±°λ€. κ·Έλ¬κΈ° μν΄μ Stringμ λ³΅μ¬ μμ±μλ, μ°Έμ‘° μΉ΄μ΄ν°λ₯Ό μ¬λ¦¬κ³ , μλ£λ₯Ό μλ‘ μμ±ν κ²μ΄ μλλΌ, κ·Έλ₯ ν¬μΈν°λ§ μΈν
ν΄ μ£Όλ μΌμ ν΄μΌ νλ€. μ΄λ° κ³Όμ μ ꡬννλ©΄
μ΄ μ½λλ₯Ό μ¬μ©νλ μν©μ λ€μκ³Ό κ°κ³ ,
μ΄λ²μ κ·Έλ¦ΌμΌλ‘ νννλ©΄
~cpp // String ν΄λμ€μ λ³΅μ¬ μμ±μ, μ΄κΈ°ν λͺ©λ‘μΌλ‘ StringValueμ ν¬μΈν°λ₯Ό μΈν νλ€. String::String(const String& rhs): value(rhs.value) { ++value->refCount; // μ°Έμ‘° μΉ΄μ΄ν°λ₯Ό μ¬λ¦°λ€. }
~cpp String s1("More Effective C++"); String s2 = s1;
μ¬κΈ°μμ μμ μ μ°Έμ‘°μΈκΈ°κ° μ μ©λμ§ μμ String ν΄λμ€λ³΄λ€ λ ν¨μ¨μ΄ λμ μ§λ€λ μ μ΄λ€. μ΄ μ±
μ λ°μ κ³μ μΈκΈνλ―μ΄, μμ±κ³Ό νκ΄΄ κ°μ μκ°κ³Ό, 곡κ°μ λ§μ λΉμ©μ μλͺ¨νλ μμ΄ μλ, ν΄λΉ ν¬μΈν°λ§μ 볡μ¬νλ―λ‘, μΌλ¨, μμ±μμ λΉμ©μ μλλ€.
μμ±μμ μμ¬μ΄ ꡬνκ°μ΄ νκ΄΄μ ꡬνλ 그리 μ΄λ €μ΄ μΌμ΄ μλλ€. StringValueμ νκ΄΄λ, μλ‘κ° μ΅λν μ¬μ©νκ³ , κ°μ΄ νκ΄΄ μμ μ μ°Έμ‘° μΉ΄μ΄ν°κ°(reference counter:μ΄ν μ°Έμ‘° μΉ΄μ΄ν°λ§) 1μΈ κ²½μ° λμ΄μ μ¬μ©νλ κ°μ²΄κ° μμΌλ―λ‘ νκ΄΄νλλ‘ κ΅¬μ±νλ€.
νκ΄΄μμ ν¨μ¨μ λΉκ΅ν΄λ μμ, λ§μ°¬κ°μ§μ΄λ€. deleteκ° λΆλ¦¬λ μμ μ ν΄λΉ κ°μ²΄κ° λ μ΄μ νμ μμλλ§ μ κ±°νλ κ²μ΄κΈ° λλ¬Έμ λΉμ©μ μλμ μλ€.
~cpp class String { public: ~String(); ... }; String::~String() { if (--value->refCount == 0) delete value; // μ°Έμ‘° μΉ΄μ΄ν°κ° 1μΈ μν }
λ€μμ ꡬνν΄μΌν μ¬νμ ν λΉ(assignment)κ΄λ ¨ν ꡬν μ¦ operator= μ΄λ€. λ³΅μ¬ μμ±μ(copy constructor)λ₯Ό νΈμΆμ΄ μλ ν λΉμ λ€μκ³Ό κ°μ΄ μ μΈλκ³ ,
λ€μκ³Ό κ°μ΄ μ¬μ©λλ©°
μ΄κ²μ ꡬνμ μ½κ°μ 볡μ‘νλ°, μ΄μ λ μμ±κ³Ό νκ΄΄κ° λμμ μμ΄μΌ νλ μν©μ κ³ λ €ν΄μΌ νκΈ° λλ¬Έμ΄λ€. κ·Έλλ μμ§ μμΌλ‘ λ€λ£¨μ΄μΌν λ΄μ©μ λΉν΄ μλΉν κ°λ¨ν νΈμ΄λ€. μμΈν μ€λͺ
μ μμ€μ μ£Όμμ μ°Έκ³ νλΌ
~cpp class String { public: String& operator=(const String& rhs); ... };
~cpp s1 = s2;
~cpp String& String::operator=(const String& rhs) { if (value == rhs.value) { // μ΄λ―Έ λ κ°μ²΄κ° κ°μ κ°μ κ°λ¦¬ν¨λ€λ©΄, return *this; // νΉλ³ν ν μΌμ μλ€. } if (--value->refCount == 0) { // νμ¬ κ°μ΄ μμ μΈμ μ무λ μ°Έμ‘°νκ³ delete value; // μμ§ μλ€λ©΄ μμ νλ€. } value = rhs.value; // μλ£λ₯Ό 곡μ νλ€. ++value->refCount; // μ°Έμ‘° μΉ΄μ΄ν°λ₯Ό μ¬λ¦°λ€. return *this; // μ΄κ±΄ μμμ --+ }
1.3. Copy-on-Write : μ°κΈ°μ κΈ°λ°ν λ³΅μ¬ ¶
μ°Έμ‘°μΈκΈ°κ° μ μ©λ λ¬Έμμ΄μ λνμ¬ λλ¬ λ΄€λλ°, μ΄λ²μλ λ°°μ΄μ κ΄ν(array-bracket) μ°μ°μλ€ "[]" μ΄λ
μλ€μ κ΄ν΄μ μκ°ν΄ 보μ. ν΄λμ€μ μ μΈμ λ€μκ³Ό κ°λ€.
const Stringμ λν κ°μ μ£Όλ κ²μ μλμ κ°μ΄ κ°λ¨ν ν΄κ²°λλ€. λ΄λΆ κ°μ΄ μλ¬΄λ° μν₯μ λ°μ κ²μ΄ μμ κ²½μ°μ΄κΈ° λλ¬Έμ΄λ€.
(μ΄ ν¨μλ μλμ C++μμ λ°°μ΄μ μ¬μ© κ°λ
κ³Ό κ°μ΄, indexμ μ ν¨μ±μ μ κ²νμ§ μλλ€. μ΄μ λν κ°μμ μ°Έμ‘° μΈκΈ°μ μ£Όμ μ λ¨μ΄μ Έ μκ³ , μΆκ°νλ κ²λ 그리 μ΄λ €μ΄μΌμ΄ μλλΌ μΌλ¨μ μ μΈνλ€.)
~cpp class String { public: const char& operator[](int index) const; // const Stringμ λνμ¬ char& operator[](int index); // non-const Stringμ λνμ¬ ... };
~cpp const char& String::operator[](int index) const { return value->data[index]; }
νμ§λ§ non-constμ operator[]λ μ΄κ²(const operator[])μ μμ ν λ€λ₯Έ μν©μ΄ λλ€. μ΄μ λ non-const operator[]λ StringValueκ° κ°λ¦¬ν€κ³ μλ κ°μ λ³κ²½ν μ μλ κΆνμ λ΄μ£ΌκΈ° λλ¬Έμ΄λ€. μ¦, non-const operator[]λ μλ£μ μ½κΈ°(Read)μ μ°κΈ°(Write)λ₯Ό λ€ νμ©νλ€.
μ°Έμ‘° μΈκΈ°κ° μ μ©λ Stringμ μμ ν λ μ‘°μ¬νκ² ν΄μΌ λλ€. κ·Έλμ μΌλ¨ μμ ν non-const operator[]λ₯Ό μννκΈ° μνμ¬ μμ operator[]λ₯Ό μνν λ λ§λ€ μλ‘μ΄ κ°μ²΄λ₯Ό μμ±ν΄ λ²λ¦¬λ κ²μ΄λ€. κ·Έλμ λ§λ κ²μ΄ λ€μκ³Ό κ°μ λ°©λ²μΌλ‘ νκ³ , μ€λͺ
μ μ£Όμμ λ μμΈν
μ΄κ²μ λΆμ‘±ν μ μ΄ μλ€. λ€μ κ³Όμ μμ 보κ°νλ€.
~cpp String s; ... cout << s[3]; // μ΄κ±΄ μ½κΈ°(Read) s[5] = 'x'; // μ΄κ±΄ μ°κΈ°(Write)
~cpp char& String::operator[](int index) // non-const operator[] { // if we're sharing a value with other String objects, // break off a separate copy of the value for ourselves // λ§μ½ λ€λ₯Έ κ°μ²΄μ μλ£λ₯Ό 곡μ νμ§ μκ³ μλ€λ©΄, μλ£λ₯Ό λ ΈμΆ μμΌλ // μκ΄μ΄ μλ€. if (value->refCount > 1) { // if μμͺ½μ μλ‘μ΄ κ°μ²΄λ₯Ό μμ±ν΄μΌ ν κ²½μ° --value->refCount; // μλ‘μ΄ κ°μ²΄μ μμ±μ μν΄μ νμ¬ μ°Έμ‘°νλ // μλ£μ refCountλ₯Ό κ°μ μν¨λ€. value = new StringValue(value->data); // νμ¬ μλ£μ μ¬λ³Έμ λ§λ€μ΄ // μ΄κ²μ κ°λ¦¬ν¨λ€. } // μ΄μ , μ무λ 곡μ νκ³ μμ§ μμ StringValueμ κ°μ²΄ // λ΄λΆμ λ¬Έμμ΄μ ν λΆλΆμ λ°ννλ€. return value->data[index]; }
μ΄λ¬ν μκ°μ μ»΄ν¨ν° κ³Όνμμ μ€λ«λμ λ€λ£¨μ΄ μ Έμλ κ²μ΄λ€. νΉνλ OS(operating system)μ€κ³μμ Processκ° κ³΅μ νκ³ μλ λ°μ΄ν°λ₯Ό κ·Έλ€μ΄ μμ νκ³ μ νλ λΆλΆμ 볡μ¬ν΄μ μ κ·Όμ νλ½ λ°λ 루ν΄μμ λ§μ΄ μ°μΈλ€. νμ΄ μ΄λ¬ν κΈ°μ μ κ΄ν΄μ copy-on-write(μ°κΈ°μ κΈ°λ°ν 볡μ¬, μ΄ν copy-on-writeλ₯Ό κ·Έλ₯ μ΄λ€.) λΌκ³ λΆλ₯Έλ€.
1.4. Pointers, References, and Copy-on-Write : ν¬μΈν°, μ°Έμ‘°, μ°κΈ°μ κΈ°λ°ν λ³΅μ¬ ¶
copy-on-writeλ₯Ό ꡬνν λ μ νμ±κ³Ό ν¨μ¨μ±, λλ€ λ§μ μν€λ νΈμ΄λ€. νμ§λ§ νμλ°λΌλ€λλ무λΊκ° μλλ°, λ€μ μ½λλ₯Ό μκ°ν΄ 보μ.
μ΄λ₯Ό λκ° κ·Έλ¦Όμ λνλ΄ λ³΄λ©΄ pκ° Helloμ eλ₯Ό κ°λ¦¬ν€λ μ΄μ λμ λλμΌ κ²μ΄λ€.
~cpp String s1 = "Hello"; char *p = &s1[1];
κ·Έλ¬λ©΄ μ΄λ²μλ μ¬κΈ°μ νμ€λ§ λ§λΆμ¬ λ³Έλ€.
String λ³΅μ¬ μμ±μκ° μλ§ s2κ° s1μ StringValueλ₯Ό 곡μ νκ² λ§λ€κ²μ΄λ€. κ·Έλμ λΉμκ³Ό κ°μ κ·Έλ¦ΌμΌλ‘ ννλ κ²μ΄λ€.
~cpp String s2 = s1;
κ·Έλμ λ€μκ³Ό κ°μ ꡬ문μ μ€ννλ€λ©΄
Stringμ λ³΅μ¬ μμ±μλ μ΄λ¬ν μνλ₯Ό κ°μ§ν λ°©λ²μ΄ μλ€. μμμ 보λ―μ΄, s2κ° μ°Έκ³ ν μ μλ μ 보λ λͺ¨λ s1μ λ΄λΆμ μλλ°, s1μκ²λ non-const operator[]λ₯Ό μννμλμ§μ κ΄ν κΈ°λ‘μ μλ€.
~cpp p = 'x'; // μ΄ κ²μ s1, s2λ₯Ό λͺ¨λ λ³κ²½!
μ΄λ°κ²μ ν΄κ²°ν μ μλ λ°©λ²μΌλ‘λ μ΅μν μΈκ°μ§λ₯Ό μκ°ν μ μλλ°, 첫λ²μ§Έλ μ΄κ²μ μλκ±Έλ‘ μ·¨κΈνκ³ , 무μ ν΄ λ²λ¦¬λ κ²μ΄λ€. μ΄λ¬ν μ κ·Ό λ°©ν₯μ μ°Έμ‘° μΈκΈ°κ° μ μ©λμ΄ μλ ν΄λμ€ λΌμ΄λΈλ¬λ¦¬μ μλΉν κ΄΄λ‘μμ λμ΄ μ£Όλκ²μ΄λ€. νμ§λ§ μ΄λ¬ν λ¬Έμ λ₯Ό ꡬνμμμ μμ ν 무μν μλ μλ λ
Έλ¦μ΄λ€. λλ²μ§Έλ‘ μκ°ν μ μλ λ°©λ²μ μ΄λ¬νκ²μ νμ§ λ§λλ‘ λͺ
μνλ κ²μΈλ°, μμλ 볡μ‘νλ€. μΈλ²μ§Έλ‘, λ κ²°κ΅ μ κ±°μΌλ§ ν κ²μ΄λ€. μ΄λ¬ν λΆμ μ μ κ±°λ 그리 μ΄λ ΅μ§λ μλ€. λ¬Έμ λ ν¨μ¨μ΄λ€. μ΄λ° μ€λ³΅μ κ΄λ ¨ν λ¬Έμ λ₯Ό μ κ±°νκΈ° μν΄μλ, μλ‘μ΄ μλ£ κ΅¬μ‘°λ₯Ό λ§λ€μ΄ λ΄μΌνκ³ , μ΄κ²μ μλ―Έλ κ°μ²΄κ°μ μλ‘ κ³΅μ νλ μλ£κ° μ€μ΄ λ λ€λ μλ―Έμ΄λ€. μ¦, λΉμ©μ΄ λ§μ΄ λ€μ΄κ°λ€. νμ§λ§ μ΄μ©μ μμ§ μμκΉ?
κ°λ¨ν νλκ·Έ νλλ₯Ό μΆκ°νλ κ²μΌλ‘ μ΄ λ¬Έμ λ ν΄κ²°λλ€. μ΄λ² μμ λ²μ μ 곡μ μ μ¬λΆλ₯Ό νλ½νλ sharable μΈμλ₯Ό λν κ²μ΄λ€. μ½λλ₯Ό 보μ.
λ³΅μ¬ μμ±μμμλ μ°Έμ‘° λΏλ§ μλλΌ. 곡μ λ₯Ό κ±°λΆν λ μμ κ°μν΄μΌ νλ―λ‘, μμ ν΄μΌ νλ€.
κ·Έλ¦¬κ³ μ΄ shareableμΈμλ non-const operator[]κ° νΈμΆλ λ falseλ‘ λ³κ²½λμ΄μ μ΄ν, ν΄λΉ μλ£μ 곡μ λ₯Ό κΈμ§νλ€.
λ§μ½ Item 30μ μΈκΈλλ proxy ν΄λμ€ λ°©λ²μ μ¬μ©ν΄μ μ½λ μμ
κ³Ό, μ°λ μμ
μ λν κ²μ ꡬλΆνλ€λ©΄ StringValue κ°μ²΄μ μ«μλ₯Ό μ’λ μ€μΌμ μμ κ²μ΄λ€. 그건 λ€μ μ₯μμ 보μ.
~cpp class String { private: struct StringValue { int refCount; bool shareabl; // μ΄ μΈμκ° λν΄ μ‘λ€. char *data; StringValue(const char *initValue); ~StringValue(); }; ... }; String::StringValue::StringValue(const char *initValue) : refCount(1), shareable(true) // μ΄κΈ°νμμλ 곡μ λ₯Ό νλ½νλ€. { data = new char[strlen(initValue) + 1]; strcpy(data, initValue); } String::StringValue::~StringValue() { delete [] data; }
~cpp String::String(const String& rhs) { if (rhs.value->shareable) { // 곡μ λ₯Ό νλ½ν κ²½μ° value = rhs.value; ++value->refCount; } else { // 곡μ λ₯Ό κ±°λΆν κ²½μ° value = new StringValue(rhs.value->data); } }
~cpp char& String::operator[](int index) { if (value->refCount > 1) { --value->refCount; value = new StringValue(value->data); } value->shareable = false; // μ΄μ μλ£μ 곡μ λ₯Ό κΈμ§νλ€. return value->data[index]; }
1.5. A Reference-Counting Base Class : μ°Έμ‘°-μΈκΈ° κΈ°μ΄ ν΄λμ€ ¶
μ°Έμ‘°μΈκΈ°λ λ¨μ§ stringμ κ²½μ°μλ§ μ μ©νκ±ΈκΉ? λ€λ₯Έ κ°μ²΄ μμ μ°Έμ‘°μΈκΈ°λ₯Ό μ μ©ν΄μ μ¬μ©ν μλ μμκΉ? μκ°ν΄ 보면 μ°Έμ‘°μΈκΈ°λ₯Ό ꡬννκΈ° μν΄μλ μ§κΈκΉμ§μ μΈκΈμ κΈ°λ₯μ λ¬Άμ΄μ μ¬μ¬μ© κ°λ₯νκ² λ§λ€λ©΄ μ’μκ² κ°μλ°, νλ² λ§λ€μ΄ 보λλ‘ νμ.
μ μΌ μ²μμ ν΄μΌ ν μΌμ μ°Έμ‘°μΈκΈ°κ° μ μ©λ κ°μ²΄λ₯Ό μν (reference-counded object) RCObjectκ°μ κΈ°μ΄ ν΄λμ€λ₯Ό λ§λλ κ²μ΄λ€. μ΄λ ν ν΄λΌμ€λΌλ μ΄ ν΄λμ€λ₯Ό μμλ°μΌλ©΄ μλμ μΌλ‘ μ°Έμ‘°μΈκΈ°μ κΈ°λ₯μ΄ κ΅¬νλλ νμμ λ°λΌλ κ²μ΄λ€. κ·Έλ¬κΈ° μν΄μλ RCObjectκ° κ°μ§κ³ μμ΄μΌ νλ λ₯λ ₯μ μΉ΄μ΄ν°μ λν μ¦κ°μ λν λ₯λ ₯μΌ κ²μ΄λ€. κ²λ€κ° λ μ΄μ, μ¬μ©μ΄ νμ μλ μμ μμλ νκ΄΄λμ΄μΌ νκ²μ΄λ€. λ€μλ§ν΄, νκ΄΄λλ μμ μ μΉ΄μ΄ν°μ μΈμκ° 0μ΄ λ λμ΄λ€. κ·Έλ¦¬κ³ κ³΅μ νμ© νλκ·Έμ λν(shareable flag) κ΄ν κ²μ, νμ¬κ° 곡μ κ°λ₯ν μνμΈμ§ κ²μ¦νλ λ©μλμ, 곡μ λ₯Ό λ¬Άμ΄ λ²λ¦¬λ λ©μλ, μ΄λ κ²λ§ μμΌλ©΄ λ κ²μ΄λ€. 곡μ λ₯Ό νΌλ€λ κ²μ μ§κΈκΉμ§μ μκ°μΌλ‘λ λΆκ°λ₯ν κ²μ΄κΈ° λλ¬Έμ΄λ€.
μ΄λ¬ν μ μλ₯Ό λͺ¨μλͺ¨μ λΌλλ₯Ό λ§λ€λ©΄ λ€μκ³Ό κ°λ€.
RCObjectλ μμ±λκ³ , νκ΄΄λμ΄ μ§μ μμ΄μΌ νλ€. μλ‘μ΄ μ°Έμ‘°κ° μΆκ°λλ©΄ νμ¬μ μ°Έμ‘°λ μ κ±°λμ΄μΌ νλ€. 곡μ μνμ λν΄ μ¬λΆλ₯Ό μμ μμ΄μΌ νλ©°, disableλ‘ μ€μ ν μ μμ΄μΌ νλ€. νκ΄΄μμ λν μ€μλ₯Ό λ°©μ§νκΈ° μνμ¬ λ² μ΄μ€ ν΄λμ€λ νκ΄΄μλ₯Ό κ°μ ν¨μλ‘μ μΈν΄μΌ λλ€. μ¬κΈ°μμλ μμ κ°μ ν¨μ(pure virtual function)λ‘ μ μΈνλ€.
~cpp class RCObject { public: RCObject(); RCObject(const RCObject& rhs); RCObject& operator=(const RCObject& rhs); virtual ~RCObject() = 0; void addReference(); void removeReference(); void markUnshareable(); bool isShareable() const; bool isShared() const; private: int refCount; bool shareable; };
λ€μ μ½λκ° RCObjectλ₯Ό λ³ μμΈ μλ€λ μ μ λ‘, μ§κΈκΉμ§μ μκ°λ€μ κ°λ¨ν ꡬνν μ½λμ΄λ€.
~cpp RCObject::RCObject() : refCount(0), shareable(true) {} RCObject::RCObject(const RCObject&) : refCount(0), shareable(true) {} RCObject& RCObject::operator=(const RCObject&) { return *this; } RCObject::~RCObject() {} // νκ΄΄μλ κ·Έκ²μ΄ μμ κ°μ ν¨μλΌλ // νμ ꡬνλμ΄ μμ΄μΌ νλ€. void RCObject::addReference() { ++refCount; } void RCObject::removeReference() { if (--refCount == 0) delete this; } void RCObject::markUnshareable() { shareable = false; } bool RCObject::isShareable() const { return shareable; } bool RCObject::isShared() const { return refCount > 1; }
μλ¬Έ λ, λ³΅μ¬ μμ±μλ refCountλ₯Ό νμ 0μΌλ‘ μΈν
ν΄ λ²λ¦°λ€. μ¬μ€ 볡μ¬ν λλ refCountλ μκ΄μ΄ μλ€. μ΄μ λ μλ‘μ΄ κ°μ²΄μ κ°μ΄λΌ, μ΄κ²μ νμ μ΄λ€ κ°μ²΄μλ 곡μ νκ³ μμ§ μκΈ° λλ¬Έμ refCountλ₯Ό μ΄κΈ°ν μν¨λ€.
μλ¬Έ μ
, ν λΉ(assignment) μ°μ°μλ μκΉ κ³΅μ λ¬Έμ λ₯Ό λ€μ§μ΄ λ²λ¦¬λ κ² μ²λΌ 보μΈλ€. νμ§λ§ μ΄ κ°μ²΄λ κΈ°μ΄ ν΄λμ€μ΄λ€. μ΄λ€ μν©μμ μ΄λ₯Ό μ λνλ λ€λ₯Έ ν΄λμ€κ° 곡μ flagλ₯Ό λΉνμ±ν μν€λμ§ νμ ν μ μκΈ° λλ¬Έμ, μΌλ¨ μ무κ²λ νμ§ μκ³ , νμ¬μ κ°μ²΄λ₯Ό λ°ννκ² ν΄ λμλ€.
κ³μ ν΄κΉλ¦΄μ μλλ°, λ€μκ³Ό κ°μ μ½λλ₯Ό 보면
μ, RCObjectλ κΈ°μ΄ ν΄λμ€μ΄λ©°, μ°¨ν λ°μ΄ν°λ₯Ό μ μ₯νλ 곡κ°μ RCObjectμ μμμκ²μ ꡬνλμ΄ μ§λ€. κ·Έλμ opreator=μ μ λ λ ν΄λμ€μμ μν λ μ΄ μ°Έμ‘° κ°μ²΄λ₯Ό λ°κΎΈκΈ° μνμ¬, RCObject::operator= νμμΌλ‘ λΆλ¬μΌ νλ€. μ΄ν, κ±°μλ€ μμ€ μ체λ₯Ό μ΄ν΄ν΄μΌ νλ€. ν΄λΉ RCObjectλ₯Ό μ΄μ©ν΄μ μ λλ ν΄λμ€μ λͺ¨μμ λ€μκ³Ό κ°μΌλ©°, λͺ¨λ μ½λλ ꡬννμ§ μκ² μ§λ§, μ§κΈκΉμ§μ κ°λ
μΌλ‘ μ΄ν΄ν μ μμ κ²μ΄λ€.
μ΄ StringValueλ²μ μ μ΄μ μ 보λκ²κ³Ό κ±°μ λμΌν ννλ₯Ό 보μΈλ€.λ¨, refCountλ₯Ό λ€λ£¨λ κ²λ§μ΄ RCObjectμ λ©€λ² ν¨μλ‘μ λͺ¨λ κΈ°λ₯μ νννλ κ²μ΄λ€. μ΄ κ²μ λ ꡬ체μ μΈ μ½λλ λ€μ μ₯μμ 보μ΄λ μ€λ§νΈ ν¬μΈν°λ₯Ό μ΄μ©ν μλ μ°Έμ‘° μΉ΄μ΄ν
κΈ°λ₯μ λ§λΆμ΄λ©΄μ μ΄μ°¨νΌ λͺ¨λ μ½λλ₯Ό μμ ν κ²μ΄λ€.
~cpp sv1 = sv2; // μ΄λ»κ² sv1κ³Ό sv2μ μ°Έμ‘° μΉ΄μ΄ν°κ° μν₯ λ°μκΉ?
~cpp class String { private: struct StringValue: public RCObject { char *data; StringValue(const char *initValue); ~StringValue(); }; ... }; String::StringValue::StringValue(const char *initValue) { data = new char[strlen(initValue) + 1]; strcpy(data, initValue); } String::StringValue::~StringValue() { delete [] data; }
μ΄λ² μ£Όμ μ nested classμ λͺ¨μ΅μ 보면 그리 μ’μ 보μ΄μ§λ μμ κ²μ΄λ€.μ²μμλ μμνκ² μ§λ§, μ΄λ¬ν λ°©λ²μ μ λΉν κ²μ΄λ€. nestedν΄λμ€μ λ°©λ²μ μλ§μ ν΄λμ€μ μ’
λ₯μ€ λ¨μ§ νλ λΏμ΄λ€. μ΄κ²μ νΉλ³ν μ·¨κΈνμ§λ λ§μλΌ.
1.6. Automating Reference Count Manipulations : μλ μ°Έμ‘° μΈκΈ° λ°©λ² ¶
RCObjectλ μ°Έμ‘° μΉ΄μ΄ν°λ₯Ό 보κ΄νκ³ , μΉ΄μ΄ν°μ μ¦κ°μ ν΄λΉ ν΄λμ€μ λ©€λ² ν¨μλ‘ μ§μνλ€. νμ§λ§ μ΄κ±΄ μ λλλ λ€λ₯Έ ν΄λμ€μ μνμ¬, μμ μ½λ©μ΄ λμ΄μΌ νλ€. μ¦, μμ κ²½μ°λΌλ©΄, StirngValue ν΄λμ€μμ addReference, removeReference λ₯Ό νΈμΆνλ©΄μ, μΌμΌμ΄ μ½λ©ν΄ μ£Όμ΄μΌ νλ€. μ΄κ²μ μ¬μ¬μ© ν΄λμ€λ‘μ 보기 μμ’μλ°, μ΄κ²μ μ΄λ»κ² μλν ν μλ μμκΉ? C++λ μ΄λ° μ¬μ¬μ©μ μ§μν μ μμκΉ.
μ λ λ°μ ν΄λμ€μμ μ°Έμ‘° μΉ΄μ΄ν°μ κ΄λ ¨ν μ½λλ₯Ό μμ κΈ°, λ§μ²λΌ μ¬μ΄ μΌμ μλκ² κ°λ€. κ±°κΈ°μλ€κ° Stringκ°μ νμ ꡬνμ μν΄μλ non-const operator[]μ λ°λ₯Έ 곡μ μ¬λΆκΉμ§ λ°μ Έ μ€μΌ νμ§ λμ± λ³΅μ‘ν΄ μ§λ λ¬Έμ μ΄λ€. νμ¬ Stringμ κ°μ 보κ΄νλκ²μ StringValueμΈλ° μ΄λ κ² ννλμ΄ μλ€.
StringValue κ°μ²΄μ refCountμ μ¦κ°μ μν΄μλ μλΉν λ§μ μμ μ½λ©μ΄ λ€μ΄κ°μΌ ν κ²μ΄λ€. 볡μ¬ν λ, μ¬ ν λΉ λ°μλ, κ·Έλ¦¬κ³ ν΄λΉ κ°μ΄ νκ΄΄λμ΄ μ§λ, μ΄λ° λͺ¨λ κ²μ μλν μν€λ κ²μ΄ μ΄λ² μ₯μ λͺ©μ μ΄λ€. μ¬κΈ°μ StringValueλ₯Ό μ μ₯μ μΈκΈνλ μ€λ§νΈ ν¬μΈν° κΈ°μ μ μ μ©ν΄μ μ΄λ° μ°Έμ‘° μΈκΈ°μ κ΄ν΄μ μ¬μ¬μ©μ λμ΄ μλνλ₯Ό μμΌ λ³΄μ.
~cpp class String { private: struct StringValue: public RCObject { ... }; StringValue *value; // μ΄ Stringμ κ° ... };
μ€λ§νΈ ν¬μΈν°μ λν μ€λͺ
μ λ무 λ°©λνλ€. νμ§λ§ μ¬κΈ° RCObjectλ₯Ό κ°λ¦¬ν¬ μ€λ§νΈ ν¬μΈν°κ° κ°μ§κ³ μμ λ₯λ ₯μ λ©€λ² μ ν(->), μμ°Έμ‘°(deferencing, *) μ°μ°μ μ λλ§ μμΌλ©΄ μΆ©λΆνλ€. λ¬Όλ‘ λ³΅μ¬λ, μμ±μ κΈ°λ³Έμ΄κ³ λ§μ΄λ€. μ°Έμ‘° μΈκΈ°λ₯Ό μν μ€λ§νΈ ν¬μΈν° ν
νλ¦Ώμ RCPtrμ΄λΌκ³ λͺ
λͺ
νκ³ , κΈ°λ³Έμ μΈ λΌλλ₯Ό λ€μκ³Ό κ°μ΄ ꡬμ±νλ€.
μμμ μΈκΈνλ―μ΄, ν
νλ¦Ώμ λͺ©μ μ RCObjectμ refCountμ μ¦κ°μ μλννκΈ° μν κ²μ΄λ€. μλ₯Ό λ€μ΄μ, RCPtrμ΄ μμ±λ λ κ°μ²΄λ μ°Έμ‘° μΉ΄μ΄ν°λ₯Ό μ¦κ°μν€ν€ μν κ²μ΄κ³ , RCPtrμ μμ±μκ° μ΄λ₯Ό μννκΈ° λλ¬Έμ μ΄μ μ²λΌ μΌμΌμ΄ μ½λ©ν νμκ° μμ κ²μ΄λ€. μΌλ¨, μμ± λΆλΆμμμ μ¦κ°λ§μ μκ°ν΄ λ³Έλ€.
곡ν΅λ μ½λλ₯Ό init()μΌλ‘ λ¬Άμλλ°, μ΄λ° κ²½μ° μ νν λμνμ§ μμμ μλ€. initν¨μκ° μλ‘μ΄ λ³΅μ¬λ³Έμ νμλ‘ ν λκ° κ·Έκ²μΈλ°, 곡μ λ₯Ό νμ©νμ§ μμ κ²½μ°μ 볡μ¬νλ λ°λ‘ μ΄λΆλΆ,
opinteeμ νμ pointer-to-Tμ΄λ€. μλ§ Stringν΄λμ€μμλ μ΄κ²μ΄ String::StringValueμ λ³΅μ¬ μμ±μ μΌκ²μΈλ°, μ°λ¦¬λ StringValueμ λ³΅μ¬ μμ±μλ₯Ό μ μΈν΄ μ£Όμ§ μμλ€. κ·Έλμ μ»΄νμΌλ¬κ° μλμ μΌλ‘ C++λ΄μ κ·μΉμ μ§ν€λ©΄μ λ³΅μ¬ μμ±μλ₯Ό λ§λ€μ΄ λΌκ²μ΄λ€. κ·Έλμ 볡μ¬λ μ€μ§ StringValueμ data ν¬μΈν°μ ν΄λΉνλ κ²λ§μ΄ μ΄λ£¨μ΄ μ§κ²μ΄λ€. dataλ 볡μ¬κ° μλ μ°Έμ‘°κ° νν΄ μ§κ²μ΄λ€. μ΄λ¬ν μ΄μ λ‘ μ΄ν, μμ±λλ λͺ¨λ νλμ€μ λ³΅μ¬ μμ±μκ° μΆκ°λμ΄μΌ νλ€.
~cpp // T κ°μ²΄λ₯Ό κ°λ¦¬ν€κΈ° μν μ€λ§νΈ ν¬μΈν° ν΄λμ€ ν νλ¦Ώ // μ¬κΈ°μμ Tλ RCObjectλ, μ΄κ²μ μμ λ°λ ν΄λμ€μ΄λ€. template<class T> class RCPtr { public: RCPtr(T* realPtr = 0); RCPtr(const RCPtr& rhs); ~RCPtr(); RCPtr& operator=(const RCPtr& rhs); T* operator->() const; // Item 28 μ°Έκ³ T& operator*() const; // Item 28 μ°Έκ³ private: T *pointee; // μλμ ν¬μΈν°λ₯Ό κ°λ¦¬ν€κΈ°μν // λλ―Έ(dumb) ν¬μΈν° pointer this void init(); // 보ν΅μ μ΄κΈ°ν λ£¨ν΄ };
~cpp template<class T> RCPtr<T>::RCPtr(T* realPtr): pointee(realPtr) { init(); } template<class T> RCPtr<T>::RCPtr(const RCPtr& rhs): pointee(rhs.pointee) { init(); } template<class T> void RCPtr<T>::init() { if (pointee == 0) { // λ§μ½ λλ―Έ(dumb)ν¬μΈν°κ° nullμ΄λΌλ©΄ return; } if (pointee->isShareable() == false) { // 곡μ λ₯Ό νμ©νμ§ μμΌλ©΄ pointee = new T(*pointee); // 볡μ¬λ₯Ό νλ€. } pointee->addReference(); // μλ‘μ΄ μ°Έμ‘° μΉ΄μ΄ν°λ₯Ό μ¬λ¦°λ€. }
~cpp pointee = new T(*pointee);
RCPtr<T>μ μ νν μνμ μν΄μ Tλ λ³΅μ¬ μμ±μλ₯Ό κ°μ§κ³ μμ΄μ, λ
립μ μΌλ‘ 볡μ¬λ₯Ό μνν΄μΌ νλ€.(λ€λ₯Έ λ§λ‘ deep copyκ° μ΄λ£¨μ΄ μ ΈμΌ νλ€.)
μ΄λ¬ν deep-copy λ³΅μ¬ μμ±μμ μ‘΄μ¬λ RCPtr<T>κ° κ°λ¦¬ν€λ Tμ κ΅ν λλ κ²μ΄ μλλΌ, RCObjectλ₯Ό μμνλ ν΄λμ€μλ μ§μλμ΄μΌ νλ€. μ¬μ€ RCPtr κ°μ²΄ κ΄μ μμ λ³Όλλ μ€μ§ μ°Έμ‘° μΈκΈ°λ₯Ό νλ κ°μ²΄λ₯Ό κ°λ¦¬ν€κΈ°λ§ νλ κ΄μ μμ μ΄κ²μ λ©λν μ μλ μ¬μ€μΌμ§ λͺ¨λ₯Έλ€. κ·Έλ μ§λ§ μ΄λ¬ν μ¬μ€μ΄ κΌ λ¬Έμν λμ΄ ν΄λΌμ΄μΈνΈμκ² μλ €μ ΈμΌ νλ€.
~cpp class String { private: struct StringValue: public RCObject { StringValue(const StringValue& rhs); ... }; ... }; String::StringValue::StringValue(const StringValue& rhs) { data = new char[strlen(rhs.data) + 1]; // μ΄ λΆλΆμ΄ deep copyμ strcpy(data, rhs.data); // μν λΆλΆμ΄λ€. }
λ§μ§λ§ RCPtr<T>μμμ κ°μ±μ Tμ λν νμ κ΄ν κ²μ΄λ€. μ΄κ²μ νμ€νκ² λ³΄μΈλ€. κ²°κ΅ pointeeλ T* νμΌλ‘ μ μΈλλλ°, pointeeλ μλ§ Tλ‘ λΆν° μ λλ ν΄λμ€ μΌμ§ λͺ¨λ₯Έλ€. μλ₯Ό λ€μλ©΄ λ§μ½ λΉμ μ΄ SepcialStringValueλΌλ String::StringValueμμ μ λλ ν΄λμ€κ° μ‘΄μ¬ νλ€λ©΄
μΌλ¨ μ°λ¦¬λ Stringμ RCPtr<StingValue> ν¬μΈν°λ‘ SpecialStringValue κ°μ²΄λ₯Ό κ°λ¦¬ν€λ μνλ‘ λ§λ€μ΄μ ν¬ν¨μν¬μ μλ€. μ΄λ¬ν κ²½μ°μ μ°λ¦¬κ° μνλ initκ° λμ§ μλλ€.
μ¦, SepcialStringValueμ λ³΅μ¬ μμ±μλ₯Ό λΆλ₯΄κΈΈ μνλλ°, StringValueμ λ³΅μ¬ μμ±μκ° λΆλ¦°λ€. μ°λ¦¬λ μ΄λ¬ν κ²μ κ°μ λ³΅μ¬ μμ±μλ₯Ό μ¨μ (Item 25 μ°Έκ³ ) ν μ μλ€. νμ§λ§, μ΄κ²μ λμμΈλ μλν κ²μ΄ μλκΈ° λλ¬Έμ, μ΄λ¬ν κ²½μ°μ λν΄μλ λ©λν μκ° μλ€.
~cpp class String { private: struct StringValue: public RCObject { ... }; struct SpecialStringValue: public StringValue { ... }; ... };
~cpp pointee = new T(*pointee); // T λ StringValueμ΄λ€, νμ§λ§ // pointeeκ° κ°λ¦¬ν€λ건 SpecialStringValeμ΄λ€.
μ΄μ , μμ±μμ κ΄ν λ΄μ©μ λ²μ΄λ, ν λΉ(assignment) μ°μ°μμ κ΄ν λ΄μ©μ λ€λ£¬λ€. ν λΉ κ²½μ°λ 곡μ μ κ²½μ°λ₯Ό μκ°ν΄μΌ νκΈ° λλ¬Έμ κΉλ€λ‘κ² λ μ μλλ°, λ€νμ€λ½κ² μ΄λ―Έ κ·Έλ¬ν κ³Όμ μ initμ 곡ν΅μ μΌλ‘ λ€μ΄ μκΈ° λλ¬Έμ μ½λκ° κ°λ¨ν΄ μ§λ€.
νκ΄΄μλ γ΄κ°λ¨νλ€. κ·Έλ₯ μ°Έμ‘° μΉ΄μ΄ν° νλλ₯Ό κ°μνλ©΄ λλ€.
μ£Όμμμμ κ°μ΄ removeReference() λ μ°Έμ‘° μΉ΄μ΄ν°κ° 0μ΄λλ©΄ ν΄λΉ κ°μ²΄λ₯Ό νκ΄΄νλ€.
~cpp template<class T> RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs) { if (pointee != rhs.pointee) { // λμ΄ κ°μ κ°μ²΄λ₯Ό 곡μ νλ©΄ // ν λΉμ μλ΅νλ€. if (pointee) { pointee->removeReference(); // νμ¬ μ°Έμ‘° κ°μ²΄ μ°Έμ‘° μΉ΄μ΄ν° κ°μ or νκ΄΄ } pointee = rhs.pointee; // κ°λ¦¬ν€λ μ°Έμ‘°λ₯Ό μκΈ΄λ€. init(); // 곡μ κ° λΆκ°λ₯ ν κ²½μ°λ μλ£λ₯Ό // μμ±νκ³ , μ΄μ°λμλ μ°Έμ‘°λ₯Ό μ¦κ° } return *this; }
~cpp template<class T> RCPtr<T>::~RCPtr() { if (pointee)pointee->removeReference(); // μμμ νκ΄΄λ¨ }
λ§μ§λ§μΌλ‘, μ΄μ μ€λ§νΈ ν¬μΈν°μ λ°±λ―ΈμΈ ν¬μΈν° νλ΄λ΄λ λΆλΆμ΄λ€.
~cpp template<class T> T* RCPtr<T>::operator->() const { return pointee; } template<class T> T& RCPtr<T>::operator*() const { return *pointee; }
1.7. Putting it All Together : μ§κΈκΉμ§μ λ°©λ²λ‘ μ 리 ¶
λλμ΄ λμ΄λ€. μ€λ§νΈ ν¬μΈν°μ, κΈ°μ΄ ν΄λμ€λ‘ μ΄μ μ¬μ¬μ© κ°λ₯ν μ°Έμ‘°μΈκΈ°λ₯Ό ꡬνν μ μλ€. μ§κΈκΉμ§ νλνλ λ§λ€μ΄μ¨ κ²μ μ΄λ²μ λͺ¨λ ν©μ³μ ννν΄ λ³΄μ.
λ¨Όμ , RCObjectμ RCPtrμ μ΄μ©ν΄μ Stringμ ꡬνν μ°Έμ‘°μΈκΈ°μ κ°λ
λλ₯Ό μμ 보μ.
μ΄λ¬ν κ°λ΅λλ λ€μκ³Ό κ°μ ν΄λμ€λ‘ μ μ λμ΄ μ§λ€.
λλ€μμ λΆλΆμμ μ°λ¦¬λ μ΄λ―Έ λ§λ€ κ²μ κ·Έλλ‘ μΌλ€. κ·Έλμ νΉλ³ν μ κ²½μ¨μΌ ν κ²μ μλ€. μ μ ν΄μΌ ν κ²μ String::StringValueμ 보μ΄λ init ν¨μμμ μ κ²½ μ¨μΌ νλ€.
~cpp template<class T> // Tλ₯Ό κ°λ¦¬ν€λ μ€λ§νΈ ν¬μΈν° class RCPtr { // μ¬κΈ°μμ Tλ RCObjectλ₯Ό μμν΄μΌ νλ€. public: RCPtr(T* realPtr = 0); // μ΄κΈ°ν, μμ±μ κ²Έ(κΈ°λ³Έκ° λλ¬Έμ) RCPtr(const RCPtr& rhs); // λ³΅μ¬ μμ±μ ~RCPtr(); RCPtr& operator=(const RCPtr& rhs); // ν λΉ μ°μ°μ T* operator->() const; // ν¬μΈν° νλ΄ T& operator*() const; // ν¬μΈν° νλ΄ private: T *pointee; // λλ―Έ(dumb) ν¬μΈν° void init(); // μ°Έμ‘° μΈκΈ° μ΄κΈ°ν(μ°Έμ‘° μΉ΄μ΄ν° μ¦κ°) }; class RCObject { // μ°Έμ‘°μΈκΈ°μ κΈ°μ΄ ν΄λμ€ public: void addReference(); // μ°Έμ‘° μΉ΄μ΄ν° μ¦κ° void removeReference(); // μ°Έμ‘° μΉ΄μ΄ν° κ°μ void markUnshareable(); // 곡μ λ§κΈ° bool isShareable() const; // 곡μ ν΄λ λλκ° λ¬»κΈ° bool isShared() const; // νμ¬ κ³΅μ μ€μΈκ° 묻기 protected: RCObject(); // μμ±μ RCObject(const RCObject& rhs); // λ³΅μ¬ μμ±μ RCObject& operator=(const RCObject& rhs); // ν λΉ μ°μ°μ virtual ~RCObject() = 0; // μμ κ°μ νκ΄΄μ // (μμμ§λ§ λ°λμ ꡬνλμ΄μΌ νλ€.) private: int refCount; // μ°Έμ‘° μΉ΄μ΄ν° bool shareable; // 곡μ νλμ€(곡μ νμ© μ¬λΆ) }; // μ²μ λ³΄λ€ λ§μ΄ λΉ μ§ Stringκ°μ§ μμκ°? ^^; class String{ // application κ°λ°μκ° μ¬μ©νλ ν΄λμ€ public: String(const char *value = ""); // μμ±μ, μ΄κΈ°ν const char& operator[](int index) const; // const operator[] char& operator[](int index); // non-const operator[] private: // ν΄λμ€ λ΄λΆμ ννμ μν λ¬Έμμ΄ κ° struct StringValue: public RCObject { char *data; // λ°μ΄ν° ν¬μΈν° StringValue(const char *initValue); // μμ±μ StringValue(const StringValue& rhs); // λ³΅μ¬ μμ±μ void init(const char *initValue); // μ°Έμ‘° μΈν ~StringValue(); // νκ΄΄μ }; RCPtr<StringValue> value; // StringValueμ μ€λ§νΈ ν¬μΈν° };
μ μ€μν μ΄ μμ΄ν
μ μ²μ μμν λ Stringν΄λμ€μ μΈν°νμ΄μ€μ λ€λ₯Έ μ μ, λ³΅μ¬ μμ±μλ μ΄λ μλκ°? ν λΉ(assignment) μ°μ°μλ μ΄λ μλκ°? νκ΄΄μλ μ΄λ μλκ°? μ λ§ μ¬κ°ν μλͺ»μΌλ‘ 보μ΄μ§ μλκ°?νμ§λ§ κ±±μ ν κ²μλ€. μ¬μ€ μ΄ κ΅¬ν ννλ μμ νλ€. λ§μ½ μ΄μ λ₯Ό λͺ¨λ₯΄κ² μΌλ©΄, C++μ μ’λ 곡λΆν΄λΌ. (μμ±μμ£Ό:μ΄λ° κ±΄λ°©μ§ λ§ν¬λ‘ λ°κΎΈλ..)
μ΄μ λ μ΄λ¬ν ν¨μλ€μ΄ λμ΄μ νμ μλ€. λ¬Όλ‘ μμ§ Stringκ°μ²΄μ 볡μ¬λ μ§μλλ€. 볡μ¬λ μ°Έμ‘°μΈκΈ°λ₯Ό κΈ°λ°ν StringValueκ°μ²΄μμ μ΄λ£¨μ΄ μ§λ κ²μΌλ‘, Stringν΄λμ€λ λ€μ΄μ± μ΄λ° κ²μ μν΄μ νμ€λ μ½λ©ν νμκ° μλ€. κ·Έ μ΄μ λ μ΄μ μ»΄νμΌλ¬κ° λ§λ€ λ³΅μ¬ μμ±μμκ² λͺ¨λ 맑겨 λ²λ¦¬λ©΄ κΈ°νμ κ²λ€μ λͺ¨λ μλμΌλ‘ μμ±λλ€. RCPtrμ μ€λ§νΈ ν¬μΈν°μ΄λ€. κ·Έμ¬μ€μ κΈ°μ΅νλΌ, 볡μ¬μ λͺ¨λ μ€λ§νΈ ν¬μΈν°κ° μ°Έμ‘°λ₯Ό κ΄λ¦¬ν΄μ€λ€.
μ, μ΄μ μ 체μ ꡬνμ½λλ₯Ό 보μ¬μ€ μ°¨λ‘μ΄λ€. λ¨Όμ RCObjectμ ꡬν μν©μ΄λ€.
λ€μμ RCPtrμ ꡬν μ½λμ΄λ€.
λ€μμ String::StringValueμ ꡬν μ½λμ΄λ€.
μ΄μ λͺ¨λ κ±Έ κ°μΈλ String ν΄λμ€μ ꡬν μ½λμ΄λ€.
μ΄ Stringν΄λμ€λ₯Ό μν μ½λμ, κ·Έλ₯ λλ―Έ(dumb)ν¬μΈν°λ₯Ό μ¬μ©ν ν΄λμ€(μ²μμ μ°Έμ‘°μΈκΈ° ꡬννκ²)μλ λκ°μ§μ ν° μ°¨μ΄μ μ΄ μλ€. 첫λ²μ§Έλ‘ μ΄ ν΄λμ€μ μ½λκ° κ΅μ₯ν μ λ€λ μ μ΄λ€. μ΄μ λ, RCPtrμ΄ μ°Έμ‘°μΈλ μμ
μ λͺ¨λ λ§‘μμ μ΄λ€. λλ²μ§Έλ‘λ μ€λ§νΈ ν¬μΈν°λ‘ κ΅μ²΄νμ§λ§, Stringμ μ½λκ° κ±°μ μ μ§λλ€λ μ μ΄λ€. μ¬μ€ λ³νλ operator[]μμλ§ κ³΅μ μ κ²½μ°λ₯Ό 체ν¬νλ λ£¨ν΄ λλ¬Έμ λ°λμλ€. μ΄λ κ² μ€λ§νΈ ν¬μΈν°λ‘μ μμ ν΄μΌνλ μμ
λ€μ΄ λ§μ΄ μ€μ΄ λ λ€.
~cpp RCObject::RCObject() : refCount(0), shareable(true) {} RCObject::RCObject(const RCObject&) : refCount(0), shareable(true) {} RCObject& RCObject::operator=(const RCObject&) { return *this; } RCObject::~RCObject() {} void RCObject::addReference() { ++refCount; } void RCObject::removeReference() { if (--refCount == 0) delete this; } void RCObject::markUnshareable() { shareable = false; } bool RCObject::isShareable() const { return shareable; } bool RCObject::isShared() const { return refCount > 1; }
~cpp template<class T> void RCPtr<T>::init() { if (pointee == 0) return; if (pointee->isShareable() == false) { pointee = new T(*pointee); } pointee->addReference(); } template<class T> RCPtr<T>::RCPtr(T* realPtr) : pointee(realPtr) { init(); } template<class T> RCPtr<T>::RCPtr(const RCPtr& rhs) : pointee(rhs.pointee) { init(); } template<class T> RCPtr<T>::~RCPtr() { if (pointee)pointee->removeReference(); } template<class T> RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs) { if (pointee != rhs.pointee) { if (pointee) pointee->removeReference(); pointee = rhs.pointee; init(); } return *this; } template<class T> T* RCPtr<T>::operator->() const { return pointee; } template<class T> T& RCPtr<T>::operator*() const { return *pointee; }
~cpp void String::StringValue::init(const char *initValue) // deep copyλ₯Ό μν΄μ { data = new char[strlen(initValue) + 1]; // μλ£λ₯Ό 볡μ¬νλ strcpy(data, initValue); // κ³Όμ κ°λ°μκ° μ κ²½μ¨μΌ νλ€. } String::StringValue::StringValue(const char *initValue) // λ³΅μ¬ μμ±μ(μλ£ κΈ°λ°) { init(initValue); } String::StringValue::StringValue(const StringValue& rhs)// λ³΅μ¬ μμ±μ(κ°μ κ°μ²΄ κΈ°λ°) { init(rhs.data); } String::StringValue::~StringValue() { delete [] data; }
~cpp String::String(const char *initValue) : value(new StringValue(initValue)) {} // valueλ RCPtr<StringValue> μ΄λ€. const char& String::operator[](int index) const { return value->data[index]; } char& String::operator[](int index) { if (value->isShared()) { value = new StringValue(value->data); } value->markUnshareable(); return value->data[index]; }
λλ¨νμ§ μμκ°? λκ° κ°μ²΄λ₯Ό μ¬μ©νμ§ μμκΉ? λκ° μΊ‘μνλ₯Ό λ°λν κΉ? νμ§λ§, μ΄λ¬ν μ κΈ°ν String ν΄λμ€μ κ΄ν κΈ°λ° μκ°μ ν΄λΌμ΄μΈνΈ μΈ‘μμ μλΆμ¬νμ μνμκ° μμ΄μΌ λ°μ΄ λλ κ²μ΄λ€. μμμΌ ν κ²μ΄ μμμλ‘ λ μ’μ μνμ΄λ€. νμ¬, Stringμ μ°λ κΈ°λ³Έ μΈν°νμ΄μ€λ λ°λκ²μ΄ μλ€. λ¨μ§ μ°Έμ‘°μΈκΈ°μ κΈ°λ₯μ΄ μΆκ°λμμ λΏμ΄λ€. κ·Έλμ ν΄λΌμ΄μΈνΈλ κΈ°μ‘΄ μ½λλ₯Ό κ³ μΉ νμκ° μλ€. λ¨, μ¬ μ»΄νμΌ(recompile)κ³Ό μ¬λ§ν¬(relink) κ³Όμ λ§μ΄ λ¨μ μμ κ²μ΄λ€. μ΄λ¬ν λΉμ©μ μ°Έμ‘°μΈκΈ°κ° μ£Όλ μ΄λμ λΉνλ©΄ μ λ§ μμ ν μλ λΉμ©μ΄λ λ§μ°¬κ°μ§μ΄λ€. μΊ‘μνλ μ λ§ μ’μκ±°λ€. (μμ±μμ£Ό:λμΌ μ΄ κ²°λ‘ μ..)
1.8. Adding Reference Counting to Exitsting Classes : μ°Έμ‘° μΈκΈ°λ₯Ό μ΄λ―Έ μ‘΄μ¬νλ ν΄λμ€μ λνκΈ° ¶
ν΄, μ°λ¦¬λ μ§κΈκΉμ§ ν₯λ―Έλ‘μ΄ ν΄λμ€μ κ΄ν΄μ λ
Όμ νλλ°, μ΄λ²μλ Widgetκ°μ μ΄λ―Έ μ μλμ΄ μλ ν΄λμ€λ₯Ό μ ν 건λλ¦¬μ§ μκ³ , μ°Έμ‘° μΈκΈ°λ₯Ό μ μ© μν¬μλ μμκΉ? κ·Έλ¬λκΉ. λΌμ΄λΈλ¬λ¦¬λ₯Ό κ³ μΉμ§ μκ³ λ§μ΄λ€. Widgetμ μ°Έμ‘° μΈκΈ°λ₯Ό μ μ© μμΌμΌ νλλ°, μμ λ°©λ² μ²λΌ RCObjectλ₯Ό Widgetμ΄ μμ μν¬ λ°©λ²μ μ ν μλ€. κ·Έλμ RCPtrλ μ μ©ν μ μλ€. λ°©λ²μ΄ μλ κ±ΈκΉ?
κ°λ¨ν λ§ν΄ μ°λ¦¬λ μ‘°κΈλ§ μ°λ¦¬μ λμμΈμ μλ΄μΌ νλ€. μΌλ¨ λ§μ½ μ°λ¦¬μ κΈ°μ‘΄ λμμΈμΈ String/StringValueκ΄κ³λ₯Ό κ³ μνλ©΄μ Widgetμ μ μ© μν€λ κ²μ κ°μ ν΄ λ³΄μ. κ·Έλ¬λ©΄ λμμΈμ λ€μκ³Ό κ°μ κ²μ΄λ€.
μ΄μ μ»΄ν¨ν° μ°νμ μΌλ‘ λ°©ν₯μ λ°κΎΈλ λΆλΆ(level)μ μΆκ°νλ λ°©λ²μΌλ‘ μ»΄ν¨ν° κ³Όνμ΄ μ²ν 컀λ€λ λ¬Έμ λ₯Ό ν΄κ²°ν΄ 보μ. μλ‘ μΆκ°λ ContHolderλ μ°Έμ‘° μΈκΈ° κΈ°λ₯μ ꡬννκ³ μμΌλ©°, λμ RCPtr ν΄λμ€ μμ RCIPtr ν΄λμ€λ‘ νλ€.("I"λ indirection(μ°ν)μ μλ―Έλ‘ λΆμκ±°λ€.) μ΄λ° λμμΈμ λ€μκ³Ό κ°μ λͺ¨μ΅μ λ³΄μΌ κ²μ΄λ€.
κΈ°λ³Έ κ°λ
μ StringValueμμ μ μ©λ λ°©μκ³Ό λΉμ·νλ€. CountHolderλ RCWidgetμ ν΄λΌμ΄μΈνΈλ‘ λΆν° ꡬν μν©μ μ¨κ²¨ λ²λ¦΄ κ²μ΄λ€. μ¬μ€ μμΈν ꡬνμ RCIPtrμ κ±°μ λ€λμ΄ μλ€. κ·Έλμ μ΄ ν΄λμ€μ ꡬν μν©μ 보μ.
RCPPtrμ RCPtrκ³Ό μ€μ§ λκ°μ§ μ μμ λ€λ₯Έλ€. 첫λ²μ§Έλ RCIPtrμ΄ μ€κ° μ‘°μ μμΈ CountHolderν΅ν΄μ μ κ·Όνλ κ²κ³Ό λ¬λ¦¬ RCPtr κ°μ²΄λ κ°μ μ§μ κ°λ¦¬ν¨λ€λ μ μ΄λ€. λλ²μ§Έλ‘λ operator->μ operator*μ μ€λ²λ‘λ(overload)ν΄μ copy-on-writeμ μλμ μΌλ‘ λμν μ μκ² νμλ€.
~cpp template<class T> class RCIPtr { public: RCIPtr(T* realPtr = 0); RCIPtr(const RCIPtr& rhs); ~RCIPtr(); RCIPtr& operator=(const RCIPtr& rhs); const T* operator->() const; // μ€λͺ κ³Ό ꡬν μ½λλ₯Ό 보μ. T* operator->(); // '' const T& operator*() const; // '' T& operator*(); // '' private: struct CountHolder: public RCObject { ~CountHolder() { delete pointee; } T *pointee; }; CountHolder *counter; void init(); void makeCopy(); // ꡬν μ½λλ₯Ό 보μ. }; template<class T> void RCIPtr<T>::init() { if (counter->isShareable() == false) { T *oldValue = counter->pointee; counter = new CountHolder; counter->pointee = new T(*oldValue); } counter->addReference(); } template<class T> RCIPtr<T>::RCIPtr(T* realPtr) : counter(new CountHolder) { counter->pointee = realPtr; init(); } template<class T> RCIPtr<T>::RCIPtr(const RCIPtr& rhs) : counter(rhs.counter) { init(); } template<class T> RCIPtr<T>::~RCIPtr() { counter->removeReference(); } template<class T> RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs) { if (counter != rhs.counter) { counter->removeReference(); counter = rhs.counter; init(); } return *this; } template<class T> void RCIPtr<T>::makeCopy() // copy-on-write μν©μ ꡬν { if (counter->isShared()) { T *oldValue = counter->pointee; counter->removeReference(); counter = new CountHolder; counter->pointee = new T(*oldValue); counter->addReference(); } } template<class T> // const μ κ·Ό; const T* RCIPtr<T>::operator->() const // copy-on-writeλ₯Ό λΉκ°μν { return counter->pointee; } template<class T> // non-const μ κ·Ό T* RCIPtr<T>::operator->() // copy-on-write κ°μ { makeCopy(); return counter->pointee; } template<class T> // const μ κ·Ό; const T& RCIPtr<T>::operator*() const // copy-on-writeλ₯Ό λΉκ°μν { return *(counter->pointee); } template<class T> // non-const μ κ·Ό T& RCIPtr<T>::operator*() // copy-on-write κ°μ { makeCopy(); return *(counter->pointee); }
κ·ΈλΌ RCIPtrμ λΉνμ¬ RCWidgetμ μλΉν ꡬνμ΄ κ°λ¨νλ€. κ±°μ λͺ¨λ κΈ°λ₯μ΄ RCIPtrμμ ꡬνλμκ³ , RCWidgetμ κ·Έκ²μ ν΅ν΄μ μΈμλ§ μ λ¬νλ©΄ λκΈ° λλ¬Έμ΄λ€.(delegate) λ§μ½ Widgetμ΄ λ€μκ³Ό κ°μ΄ μκ²Όλ€λ©΄
RCWidgetμ μλ§ μ΄λ κ² κ΅¬νλ κ²μ΄λ€.
(μμ±μμ£Ό: κΈ°ν λ΄μ©μ κ·Έλ₯ λ΄λΆμ λν μ€λͺ
μ΄λ€. μλ΅νλ€. λμ€μ μκ°μ΄λλ©΄ μΆκ°)
~cpp class Widget { public: Widget(int size); Widget(const Widget& rhs); ~Widget(); Widget& operator=(const Widget& rhs); void doThis(); int showThat() const; };
~cpp class RCWidget { public: RCWidget(int size): value(new Widget(size)) {} void doThis() { value->doThis(); } // delegateμμΌ μ€λ€. int showThat() const { return value->showThat(); } // delegateμμΌ μ€λ€. private: RCIPtr<Widget> value; };
1.9. Evaluation : νκ° ¶
μ§κΈκΉμ§, widget, string, κ°(value), μ€λ§νΈ ν¬μΈν°(smart pointer), μ°Έμ‘° μΈκΈ° κΈ°λ³Έ ν΄λμ€(reference-counting base class)μ κ΄ν΄μ ꡬ체μ μΈ λΆλΆμ λ€λ£¨μ΄ μλ€. μ΄ λͺ¨λ κ²μ μ°λ¦¬μκ² μ°Έμ‘° μΈκΈ°λ₯Ό μ μ©ν μ μλ λμ νμ κ°μ Έλ€ μ£Όμλ€. μ΄μ μ‘°κΈ μΌλ°μ μΈ μ΄μΌκΈ°λ‘, μ§λ¬Έν΄ 보μ. λ€μ λ§νμλ©΄, λ체 μΈμ μ°Έμ‘° μΈκΈ°μ κΈ°μ μ μ μ© μμΌμΌ ν κΉ?
μ°Έμ‘°μΈκΈ°μ ꡬνμ 곡μ§κ° μλλ€. λͺ¨λ μ°Έμ‘°μΈκΈ°λ μ°Έμ‘°μΈκΈ°μ λν κ·Έλ§ν λΉμ©μ μ§μΆνμΌ νλλ°, μ¬μ©μλ μ΄λ¬ν λ°©λ²λ‘ μ μ μ©μ, κ²μ¦μ μνλ€. λ¨μν 보면, μ°Έμ‘°μΈκΈ°λ λ λ§μ λ©λͺ¨λ¦¬λ₯Ό μ‘μλ¨Ήκ²λ ν μ μκ³ , λ λ§μ μ½λλ₯Ό μ‘μ λ¨Ήκ² ν μ μλ€. κ±°κΈ°μλ€ λͺ¨μλΌ, μ½λλ₯Ό λ 볡μ‘νκ² νκ³ , μ μ±λ€μ¬ λ§λ μ½λμ λνμ¬ λ§μ³ λ²λ¦΄μλ μλ€. λ§μ§λ§μ μ΅μ’
ꡬνλ String(StringValue, RCObject, RCPtrμ΄ μ μ©λ λ²μ ) ν΄λμ€ λ³΄λ€λ, λ³΄ν΅ μ‘μ‘°μΈκΈ°κ° μ μ© μλ μ½λλ€μ μ΄λ€. μ¬μ€ μ°λ¦¬κ° λμμΈν μ’λ 볡μ‘ν λμμΈμ μλ£μ 곡μ λ‘ λ μ’μ ν¨μ¨μ λμ΄ λ€μΈλ€. κ·Έκ²μ κ°μ²΄μ μμ κΆλ€μ μ£Όλ¦¬κ³ , μ°Έμ‘°μΈκΈ°μ μ¬μ¬μ© λ°©λ²μ λν μκ°λ€μ μ μνλ€. κ·ΈλΌμλ, λ€κ°μ§μ ν΄λμ€λ₯Ό μ¬μ©ν΄μΌ νκ³ , νμ€νΈνκ³ , λ¬Έμννκ³ , μ μ§ γ
μ€νλλ°μλ, νλμ ν΄λμ€λ₯Ό μμ±,λ¬Έμν,μ μ§λ³΄μ νλκ²λ³΄λ€ λ λ§μ μΌμ λΆλ΄νκ² λ§λ λ€.
μ°Έμ‘°μΈκΈ°λ 보ν΅μ κ°μ²΄λ€μ 곡μ ν΄μ μμ€ν
μ λΉμ©μ μ€μ΄κ³ μ νλ μ΅μ ν κΈ°μ μ΄λ€. μ¦, 곡μ λ₯Ό λ§μ΄ νμ§ μμ νλ‘κ·Έλ¨ κ°μ²΄μ λνμ¬ μ΄λ₯Ό μ μ©νλ©΄ λ λ§μ λΉμ©κ³Ό, λ 볡μ‘ν νλ‘κ·Έλ¨μ μμ±ν μ λ°μ μλ€λ κ²°λ‘ μ΄ λλ κ²μ΄λ€. κ·Έ λ°λλΌλ©΄, μκ°, κ³΅κ° λΉμ© λͺ¨λλ₯Ό μλΌκ² ν΄μ€ κ²μ΄λ€. κ·Έλ¬ν μν©μ μκ°ν΄ λ³Έλ€.
- μ μ μλ£λ₯Ό λ§μ κ°μ²΄λ€μ΄ μ¬μ©νκ³ μ νλ€. μ΄λ¬ν κ²½μ°μλ μμ±μμ 볡μ¬μ κ΄ν λΉμ©μ΄ λ§μ΄ λ λ€. μ΄λ° κ²½μ° μ°Έμ‘°μΈκΈ°μ μ μ©μ΄ λ λμ ν¨μ¨μ λμ΄ λΌμ μμ κ²μ΄λ€.
- Relatively few values are shared by relatively many objects.
- Relatively few values are shared by relatively many objects.
- κ°μ²΄λ₯Ό μμ±νκ³ , νκ΄΄νλλ° λμ λΉμ©μ μ§λΆν΄μΌ νκ±°λ, λ§μ λ©λͺ¨λ₯Ό μ¬μ©νλ€. μ΄λ¬ν κ²½μ° μ‘°μ°¨ μ°Έμ‘°μΈκΈ°λ λ§μ κ°μ²΄κ° 곡μ νλ©΄ ν μλ‘ λΉμ©μ μ€μ¬ μ€κ²μ΄λ€.
- Object values are expensive to create or destroy, or they use lots of memory.
- Object values are expensive to create or destroy, or they use lots of memory.
μ§κΈκΉμ§μ ꡬνμΌλ‘ μ°Έμ‘°μΈμ΄κΈ μλ£λ heapμμμλ§ μ μΈν μ μλ€. μ무리 μ§μ λ³μλ‘ μ μΈνλ€, λ΄λΆμμ μλ£λ heapμμμ μ μΈνμ¬, κ΄λ¦¬λλ€. μ νν μ μΈμ΄λ ν΄λμ€λ₯Ό λ§λ€μ΄μΌ νκ³ , κ·Έλμ νμ€ν λμνλκ° νμ ν μ μλ λ²κ·Έ μλ μ½λλ₯Ό λ§λ€μ΄μΌνλ€. κ·Έλ¦¬κ³ μ΄ μ°Έμ‘°μΈκΈ° κΈ°λ³Έν΄λμ€κ° μ°λ¦¬μ μμ μ¬λ°λ₯΄κ² λ λλ κ²μ μ¬μ© λ°©λ²μ λνμ¬ μ νν κΈ°μ μ΄ νμνλ€.
DeleteMe)μμ΄κ° μ§§μμ§ λ€μ λ΄μ©μ μ§λ£¨ν κ°μ ν λ‘ μ μ°μκ°λ€. μΆκ°ν κΈ°μ΄λ μλλ€.
2. Item 30: Proxy ¶
- Item 30: λ리μ
μ΄ μ½λλ ν©λ²μ΄λ€.:
νμ§λ§ μ°¨μμ ν¬κΈ°λ λ³μκ° λ μ μλ€. μ΄λ°κ²μ΄ μλλ€.:
κ±°κΈ°μ Heap μμμ κΈ°λ°ν ν λΉ μμ κ·μΉμ μ΄κΈλλ€.
~cpp int data[10][20]; // 2μ°¨μ λ°°μ΄ 10 by 20
~cpp void processInput(int dim1, int dim2) { int data[dim1][dim2]; // μλ¬! λ°°μ΄μ μ°¨μμ λ¨μ§ μ»΄νμΌ μ€μλ§ κ²°μ λλ€. ... }
~cpp int *data = new int[dim1][dim2]; // μλ¬!
2.1. Implementing Two-Dimensional Arrays μ΄μ°¨μ λ°°μ΄μ κ΅¬ν ¶
λ€μ°¨μμ λ°°μ΄μ C++μ λΏμλλΌ. λ€λ₯Έ μΈμ΄μμλ μ μ©νλ€. κ·Έλμ λ€μ°¨μ λ°°μ΄μ μ΅κ·Όμ μ΄κ²λ€μ μ§μνλ λ°©λ²μ λν μ€μμ±μ΄ λλλκ³ μλ€. 보ν΅μ λ°©λ²μ C++μμ νμ€ μ€μ νλμ΄λ€.(νμλ‘ν κ°μ²΄λ₯Ό νννκΈ° μν΄ ν΄λμ€λ₯Ό λ§λ λ€. νμ§λ§ μλ§κ² ꡬννκΈ°κ° μ΄λ ΅λ€. ) λ°λ‘ μ΄μ°¨μ λ°°μ΄μ λν ν
νλ¦Ώμ μ μν μ μλ€.
μνλλ°λ‘ λ°°μ΄μ μ μν μ μλ€.
νμ§λ§ μ΄λ¬ν λ°°μ΄ κ°μ²΄μ μ¬μ©μ μλ²½νμ§ μλ€. Cμ C++μμμ κΈ°λ³Έ λ¬Έλ²μ μ μ©μν¨λ€λ©΄, κ΄νΈλ₯Ό μ¬μ©ν΄μ κ°μ²΄μ indexλ₯Ό μ¬μ©ν μ μμ΄μΌ νλ€.
κ·Έλ μ§λ§ Array2Dμμ μΈν
μ€μ κ΄νμΈμλ₯Ό μ΄λ»κ² μ μνκ³ , μ¬μ©ν κΉ?
~cpp template<class T> class Array2D { public: Array2D(int dim1, int dim2); ... };
~cpp Array2D<int> data(10, 20); // μ³λ€ Array2D<float> *data = new Array2D<float>(10, 20); // μ³λ€ void processInput(int dim1, int dim2) { Array2D<int> data(dim1, dim2); // μ³λ€ ... }
~cpp cout << data[3][6];
첫λ²μ§Έ νκ³ μΆμ건 μλ§ operator[][]λ₯Ό μ μΈν΄ λ²λ¦¬λ κ²μ΄λ€. μ΄λ κ²
보μλ§μ μ΄ μ°μ°μμ μλλ₯Ό μκ²μ΄λ€. νμ§λ§ operator[][]λ건 μ μΈν μκ° μλ€. κ·Έλ¦¬κ³ λΉμ μ μ»΄νμΌλ¬μμ μ΄κ²μ κ°μνμ§ μμ κ²μ΄λ€. (μ€λ²λ‘λ(overload)μ κ΄λ ¨ν μ°μ°μλ€μ κ΄ν μ 보λ Item 7μ μ°Έκ³ νλΌ) μ°λ¦¬λ κ·ΈμΈμ λ€λ₯Έ λ°©μμ μ°ΎμμΌ νλ€.
~cpp template<class T> class Array2D { public: // μ΄λ¬ν μ μΈμ μ»΄νμΌ ν μ μλ€. T& operator[][](int index1, int index2); const T& operator[][](int index1, int index2) const; ... };
λ§μ½ λ¬Έλ² λλ¬Έμ κ³¨λ¨Έλ¦¬κ° μνλ€λ©΄, λ°°μ΄μ μ§μνλ λ§μ μΈμ΄μμ μ¬μ©νκ³ μλ λ°©λ²μ λ°λΌμ, ()λ₯Ό μ΄μ©νλ μΈν
μ€μ μ κ·Όμ λ§λ€μ΄ λ³Όμλ μλ€. ()μ μ΄μ©μ λ¨μ§ operator()λ₯Ό μ€λ²λ‘λ(overload)νλ©΄ λλ€.
ν΄λΌμ΄μΈνΈμμλ μ΄λ κ² μ¬μ©νλ€.
μ΄λ¬ν ꡬνμ μ½κ³ , λΉμ μ΄ μ¬μ©νκ³ μ νλ λ§μ μ°¨μμμ μΌλ°ν μν€κΈ°λ μ©μ΄νλ€. νμ§λ§ κ²°μ μ΄ μλλ°, Array2D κ°μ²΄λ built-in λ°°μ΄κ°μ΄ 보μ΄μ§ μλλ€λ μ μ΄λ€. μ¬μ€ μμ, κ° dataμ μΈμλ€μ λνμ¬ (3,4)κ³Ό κ°μ μ κ·Ό λ°©λ²μ ν¨μ νΈμΆκ³Ό κ°μ λͺ¨μ΅μ νκ³ μλ€.
~cpp class Array2D { public: // μ΄λ° μ¬νμ μ μ»΄νμΌ λλ€. T& operator()(int index1, int index2); const T& operator()(int index1, int index2) const; ... };
~cpp cout << data(3, 6);
FORTRANκ³Ό κ°μ΄ 보μ΄λ μ΄λ¬ν λ°°μ΄ ννλ²μ΄ λ§μμ λ€μ§ μλλ€λ©΄, index μ°μ°μμ κ°μ κ°λ
μ μΌλ‘ λ€μ λμκ° λ³Έλ€. operator[][]λ₯Ό μ¬μ©νμ§ μκ³ λ ν©λ²μ μΌλ‘ λ€μκ³Ό κ°μ΄ 보μ΄λ μ½λλ₯Ό ꡬνν μλ μμκΉ?
μ΄λ»κ² νλ©΄ λ κΉ? λ³μμΈ dataλ μ€μ λ‘ μ΄μ°¨μ λ°°μ΄μ΄ κ²°μ½ μλλ€. κ·Έκ²μ 10κ°-μΈμκ° νλμ μ°¨μμΌλ‘ λ λ°°μ΄μΌλ‘ μ£Όμ΄μ§ κ²μ΄λ€. 10κ° μΈμλ κ°κΈ° 20κ°μ μΈμλ₯Ό κ°μ§ λ°°μ΄λ‘ λμ΄ μλ€. κ·Έλμ data36μ μ€μ λ‘λ (data3)6λ₯Ό μλ―Ένλκ²μ΄λ€. λ€μ λ§νμλ©΄, dataμ λ€λ²μ§Έ μΈμμΈ λ°°μ΄μ μΌκ³±λ²μ§Έ μΈμ. μ§§κ² λ§ν΄ κ°μ μ²μ κ΄νΈμ μλ―Έλ λλ€λ₯Έ λ°°μ΄μ΄λ€. κ·Έλμ λλ²μ§Έ κ΄νΈμ μ μ©μ λλ²μ§Έμ λ°°μ΄λ‘ λΆν° μΈμλ₯Ό κ°μ§κ³ μ€λ κ²μ΄λ€.
~cpp int data[10][20]; ... cout << data[3][6];
κ°μ λ°©μμ Array2Dμ operaotr[]κ° μλ‘μ΄ κ°μ²΄μΈ, Array1Dλ₯Ό λ°νμν€λ λ°©μμΌλ‘ νμ΄λκ° λ³΄μ. μλ μ΄μ°¨μ λ°°μ΄μ μμ μ‘΄μ¬νλ, λ°νλλ μΈμ Array1Dμμ operator[]λ₯Ό μ€λ²λ‘λν μ μλ€.
μ΄λ¬κ² νλ©΄ λ€μκ³Ό κ°μ λ¬Έλ²μ΄ ν©λ²μ μ΄λ€.
μ¬κΈ°μμ data3μ Array1Dλ₯Ό μ΄μΌκΈ° νλ κ²μ΄κ³ , operator[]λ λλ²μ§Έ μ°¨μμ μμΉ (3,6)μ μλ floatλ₯Ό νΈμΆνλ€.
~cpp template<class T> class Array2D { public: // 2λ²μ§Έ μ°¨μμ μμΉνλ Array1D class Array1D { public: T& operator[](int index); const T& operator[](int index) const; ... }; // μμ 1μ°¨μ λ°°μ΄ κ°μ²΄ Array1D Array1D operator[](int index); const Array1D operator[](int index) const; ... };
~cpp Array2D<float> data(10, 20); ... cout << data[3][6]; // μ³λ€.
Array2D ν΄λμ€μ ν΄λΌμ΄μΈνΈλ Array1Dν΄λμ€μ κ΄ν΄μ μ κ²½ μΈνμ μλ€. μ΄λ¬ν κ°μ²΄λ 1μ°¨μμ λ°°μ΄μλν κ°μ²΄μ νμ€μ΄μ§λ§, κ°λ
μ μΌλ‘λ μ‘΄μ¬νμ§ μλλ€. μ΄κ²λ€μ μ€μ λ‘ μ°λ κ·Έλ¬ν ν΄λΌμ΄μΈνΈλ€μ μ΄μ°¨μ λ°°μ΄μ μ νν νλ‘κ·Έλ¨ νλ€. C++μ μλ±ν μ§μ λ§μ‘±μν€κΈ° μνμ¬, μΌμ°¨μ λ°°μ΄μ λ€λ£¨λλ° λ¬Έλ²μ μΌλ‘ μ νν ꡬνν Array2Dμ ν΄λΌμ΄μ΄νΈλ€μ΄ κ±±μ νλ μΌμ΄ μλ€.
Array2Dμ ν΄λΌμ΄μΈνΈμ μν΄ μ¬μ©λμ΄μ§λ κ°λ
μ μΈ λͺ¨λΈμ λΆμ λ‘, Array1D κ°κ°μ κ°μ²΄λ 1μ°¨μ λ°°μ΄μ μλ―Ένλ€. λ€λ₯Έ κ°μ²΄λ₯Ό μν΄ μ‘΄μ¬νλ κ°μ²΄λ€μ λ³΄ν΅ proxy objectλΌκ³ λΆλ¦¬μ΄κ³ , oproxyκ°μ²΄λ proxy classμ μν΄ νΈμΆλλ€. proxy ν΄λμ€ or μ μΈμ€ν΄μ€λ μΌμ°¨μ λ°°μ΄μ κ·Όκ°μ΄ λλλ°, κ°λ
μ μΌλ‘ μ‘΄μ¬νμ§ μμλ€. (proxy κ°μ²΄λ₯Ό μν κΈ°μ κ³Ό ν΄λμ€λ μ 체μμ λλ¨μ΄μ§ λͺ¨μ΅μ΄λ€.; κ·Έλ¬ν ν΄λμ€μ κ°μ²΄ μμ λλ‘ surrogate(λ리μ) λΌκ³ λ λΆλ¦΄ κ²μ΄λ€.
2.2. Distinguishing Reads from Writes via operator[] : operator[]μ μ°κΈ°μ κΈ°λ°ν μ½κΈ°λ₯Ό κ΅¬λ³ ¶
λ€μ°¨μ λ°°μ΄κ³Ό κ°μ μΈμ€ν΄μ€λ₯Ό λ§λλ νλ‘μμ μ¬μ©μ μΌλ°μ μ΄λ€. νμ§λ§ νλ‘μ ν΄λμ€λ€μ μΌλ° λ°°μ΄λ³΄λ€ μ μ°νμ§ λͺ»νλ€. Item 5μμ μλ₯Ό λ€μ΄ 보면 μ΄λ»κ² νλ‘μ ν΄λμ€λ€μ΄ μλνμ§ μμ μμ±μμ μ¬μ©μ λ§μμ μλμ§ λ°©λ²μ 보μ¬μ€λ€. νμ§λ§ νλ‘μ ν΄λμ€μ λ€μ±λ‘μ΄ μ¬μ©μ΄ κ°μ₯ μμλ €μ§ κ²μ λ§λ‘ operator[]μμ writeμ readλ₯Ό ꡬλΆνλ κ²μ΄λ€.
operator[]λ₯Ό μ§μνλ, μ°Έμ‘°μΈκΈ°κ° μ μ©λ λ¬Έμμ΄ νμ κ΄ν΄μ μκ°ν΄ 보μ. μμΈν μ€λͺ
μ Item 29λ₯Ό μ°Έκ³ νλΌ, λ§μ½ Item 29μ λ°©λ²λλ‘ μ°Έμ‘°μΈκΈ°μ κ°λ
μ μ μ©ν΄μ, κ·Έκ²μ λ°°μ΄μ μΌλ°ν μν€λ κ²μ μ’μ μκ°μ΄λ€.
operator[]λ₯Ό μ§μνλ λ¬Έμμ΄ νμ ν΄λΌμ΄μΈνΈμκ² λ€μκ³Ό κ°μ μ½λλ₯Ό νμ©νλ€.
operator[] λ κ°κΈ° λ€λ₯Έ λͺ©μ μΌλ‘ νΈμΆλ μ μμμ μ μνλΌ: λ¬Έμλ₯Ό μ½κ±°λ νΉμ λ¬Έμλ₯Ό μ°κ±°λ, μ½κΈ°λ rvalueμ ννλ‘ μ°μ¬μ§λλ‘ μλ €μ Έ μλ€.; κ·ΈλΌ μ°κΈ°λ lvalueνν(rμ right hand value, lμ left μ΄ν κ°μ) μΌλ°μ μΌλ‘ lvalueμ μλ―Έλ κ°μ²΄μμ κ·Έλ¬ν κ°μ²΄μ μμ μ μλ―Ένλ©°, rvalueλ μμ μ ν μ μλ κ²μ μλ―Ένλ€.
~cpp String s1, s2; // λ¬Έμμ΄κ³Ό λΉμ·ν ν΄λμ€;νλ‘μμ μ°μμ // νμ€ λ¬Έμμ΄ μΈν°νμ΄μ€λ₯Ό λ°λ₯΄λ ν΄λμ€ ννλ₯Ό // μ μ§νλ€. ... cout << s1[5]; // s1 μ½κΈ° s2[5] = 'x'; // s2 μ°κΈ° s1[3] = s2[8]; // s1 μ°κΈ°, s2 μ½κΈ°
μ΄λ¬ν μν, μ¦ perator[]μμ lvalueμ rvalueλ₯Ό ꡬλΆν΄μΌλ§ νλ€. μλνλ©΄ μ°Έμ‘°μΈκΈ°κ° μ μ©λ μλ£κ΅¬μ‘°μ κ²½μ°μ μ½κΈ°λ μ°κΈ°μ λΉνμ¬ ν¨μ¬ μ μ λΉμ©μ μλͺ¨νκΈ° λλ¬Έμ΄λ€. Item 29μμ μ°Έμ‘°μΈκΈ° κ°μ²΄μ μ°κΈ°λ μλ§ μ 체 μλ£κ΅¬μ‘°μ 볡μ¬λ₯Ό μ λνμ§λ§, μ½κΈ°λ κ°λ¨ν κ°μ λ°νμ μλ―Ένλ€κ³ μ€λͺ
νλ€. λΆννλ, operator[]μ λ΄λΆμμ, μ΄λ€μ νΈμΆ λͺ©μ μ ꡬλΆν λ°©λ²μ μλ€. operator[]λ lvalueμ rvalueμ μ°μμ μ°¨μ΄λ₯Ό ꡬλΆν μ μλ€.
"κ·Έλ μ§λ§ μ μ!" νκ³ λΉμ μ΄ λ§νλ€. "κΌ κ·Έλ΄ νμκ° μλ€. operator[]μ μμν λ κ°λ
μ λ°μλ€μ¬μ operator[]μ μ½κΈ°μ μ°κΈ°λ₯Ό ꡬλΆνλ©΄ λμ§ μμκ°?" μ΄λ¬ν λ€λ₯Έ μΈ‘λ³μΌλ‘ λΉμ μ μ°λ¦¬μκ² λ¬Έμ μ ν΄κ²° λ°©μμ μ μνλ€.
λΆννλ μ΄λ¬ν κ²μ μνλμ§ μλλ€. μ»΄νμΌλ¬λ constμ non-const λ©€λ² ν¨μμ ꡬλΆμ μ€μ§ κ·Έ κ°μ²΄κ° constμΈκ°μ μ¬λΆμ λ°λΌλ§ νλ¨νλ€. μ΄λ¬ν ꡬνμ, constꡬλ³μ λͺ©μ μ μν΄ μλ¬΄λ° μν₯μ λͺ» λΌμΉλ€.
κ·Έλ¬λ―λ‘ μ΄λ° λ°©μμ operator[]μ μ€λ²λ‘λλ μ½κΈ°μ μ°κΈ°μ ꡬλΆμ μ€ν¨νλ€.
~cpp class String { public: const char& operator[](int index) const; // μ½κΈ° μν΄ μ‘΄μ¬ char& operator[](int index); // μ°κΈ° μν΄ μ‘΄μ¬ ... };
~cpp String s1, s2; ... cout << s1[5]; // non-const operator[] νΈμΆ μλνλ©΄ // s1μ΄ non-constμ΄κΈ° λλ¬Έμ s2[5] = 'x'; // μμ non-const operator[] νΈμΆ: s2λ non-constμ΄λ€. s1[3] = s2[8]; // λλ€ non-const operator[] νΈμΆ μλνλ©΄ s1,s2λͺ¨λ // non-const κ°μ²΄μ΄λ€.
Item 29μμ μ°λ¦¬λ operator[]λ₯Ό μ°κΈ°λ₯Ό μν΄μ μ¬ λμμΈνλ€. μλ§ μ΄κ±Έ μ½κ² ν¬κΈ°ν μλ μμ κΊΌλ€.(μμ±μμ£Ό:μΌλ§λ κ³ μνλ©΄μ λ΄€λλ°, λ°κΎΈκΈ° μ«μ§.) Item 29μ λμμΈμ lvalueμ rvalueμ μ¬μ©μ ꡬλΆνλ κ²μ΄ μλλΌ, operator[]λ₯Ό νΈμΆνλ©΄ 무쑰건 μ°κΈ°λ‘ μ·¨κΈν΄ λ²λ¦¬λ κ²μ΄λ€.
operator[]κ° μ½κΈ°μ μ°κΈ°λ₯Ό κ΅¬λΆ λͺ»νμ§λ§ μΌλ¨ μ°λ¦¬λ κ°λ₯νν μ΄κ²μ ꡬνν΄ λ³΄κ³ μ νλ μ
μ₯μμ μ κ·Όν΄ λ³΄μ. operator[]κ° λ°νν μ΄νμ μ½κΈ°μ μ°κΈ°μ μνλ₯Ό μμλ΄λ λ°©λ²μ νμλ‘ νλ€. μ΄κ²μ μλ―Έλ μμ λ€λ£¨μλ, lazy evaluationμ κ°λ
κ³Ό λΉμ·νμ§ μμκΉ?
νλ‘μ ν΄λμ€λ μ°λ¦¬κ° νμν μκ°μ λ²μ΄ μ€μ μλ€. μ°λ¦¬λ operator[]μ λ°νμΈμλ₯Ό λ¬Έμλμ μ λ¬Έμμ΄μ μν νλ‘μ κ°μ²΄λ₯Ό λ°ννλλ‘ μμ ν μ μκΈ° λλ¬Έμ΄λ€. μ°λ¦¬λ μ΄λ κ² νλ‘μλ₯Ό μ¬μ©ν΄μ μκ°μ λ²μ μλ€. μ΄ νλ‘μ ν΄λμ€κ° μ½νλ, operator[]κ° μ½κΈ°μΈμ§ μ°κΈ°μΈμ§λ₯Ό μμ μλ€.
μΌλ¨ μμ€λ₯Ό 보기μ μ μ°λ¦¬κ° νλ‘μλ₯Ό μ΄λ»κ² μ¨μΌν μ§ μΈκ°μ§μ μμλ‘ λλμ΄ μκ°νμ.
- νλ‘μλ₯Ό λ§λ λ€. λ€μ λ§ν΄ λ¬Έμμ΄μμ λ¬Έμλ₯Ό λμ νλ κ²μ μλ§λλ‘ λ§λ λ€.
- νλ‘μλ₯Ό μ¨μΌν κ³³, μ¦ λ¬Έμμ΄μ κΈμλ₯Ό ν λΉν κ³³μ μ μ©νλ€. μ μ©μ ν λ νλ‘μλ operaotr[]μμ lvalueμ μ°μμΌλ‘ μ¬μ©λλ€.
- λ λ€λ₯Έ λ°©μμΌλ‘ νλ‘μλ₯Ό μ¬μ©νλ€. μ΄λ κ² μ¬μ©λλ©΄ νλ‘μλ operator[]μ λν rvalueμ μ°μμ ꡬννλ€.
~cpp class String { // μ°Έμ‘°μΈκΈ°κ° μ μ©λ λ¬Έμμ΄, Item 29μ°Έκ³ public: class CharProxy { // λ¬Έμμ νλ‘μ public: CharProxy(String& str, int index); // μμ± CharProxy& operator=(const CharProxy& rhs); // lvalue CharProxy& operator=(char c); // μ μ°μμ λ°μ operator char() const; // rvalueμ μ°μμ λ°μ // use private: String& theString; // νλ‘μμμ λ¬Έμμ΄μ μ°Έμ‘°ν κ²½μ°κ° νμν μ int charIndex; // λ¬Έμμ μΈλ±μ€ }; // Stringν΄λμ€κ° ν¬ν¨νκ³ μλ κ² const CharProxy operator[](int index) const; // const Stringμ λ°μ CharProxy operator[](int index); // non-const Stringμ μν΄μ ... friend class CharProxy; private: RCPtr<StringValue> value; };
~cpp String s1, s2; // νλ‘μλ₯Ό μ¬μ©νλ μ°Έμ‘° μΈκΈ°κ° μ μ©λ λ¬Έμμ΄ ... cout << s1[5]; // μ³λ€. s2[5] = 'x'; // μμ μ³λ€. s1[3] = s2[8]; // μμλ μλμκ°λ€.
맨μ²μμ μ΄ κ΅¬λ¬Έμ μκ°ν΄ 보μ.
s15μ ννμ CharProxy κ°μ²΄λ₯Ό λ°ννλ€. s15κ° output(<<) μ°μ°μμ λνμ¬ κ°μ²΄μ λνμ¬ μ μλκ²μ μλ€. κ·Έλμ λΉμ μ μ»΄νμΌλ¬λ operator<<μ μ μ©ν μ μλ μμμ (implicit) νλ³νμ μ°Ύλλ€. μ»΄νμΌλ¬λ κ·Έλμ νλ‘μ ν΄λμ€ λ΄λΆμ μ μΈλμ΄ μλ char()λ₯Ό μ°Ύμμ μλ€. μ»΄νμΌλ¬λ μ΄(char) νλ³νμ μννκΈ°λ₯Ό μμ²νκ³ , κ²°κ³Όμ μΌλ‘ CharProxyλ λ¬Έμλ‘ λ³νλμ΄μ μΆλ ¨λμ΄ μ§λ€. λ€μ λ§νμ§λ§, μ΄κ²μ CharProxy-to-char λ‘μ νλ³νμ΄ CharProxyλ΄λΆμ μμμ (implicit) νλ³νμ΄ μ μΈλμ΄ μκΈ° λλ¬Έμ΄λ€.
~cpp cout << s1[5];
lvalueμ μ¬μ©μ μ’ λ€λ₯΄κ² μ‘νλλ°, μ΄ κ΅¬λ¬Έμ λ€μ 보μ.
s25μ ννμ CharProxyκ°μ²΄λ₯Ό λ°ννλ€. κ·Έλ¦¬κ³ ν λΉ(assignment)μ°μ°μμ λͺ©νκ° λλ€.μ΄λ€ ν λΉ(assignment) μ°μ°μκ° λΆλ €μ§λ κ±ΈκΉ? ν λΉμ λͺ©νλ CharProxyμ΄λ€. κ·Έλμ ν λΉμ°μ°μλ CharProxy ν΄λμ€ μμμ λΆλ €μ§λ€. μ΄κ²μ μ€μν κ²μ΄λ€. μλνλ©΄ CharProxyμ ν λΉ(assignment) μ°μ°μλ₯Ό μ¬μ©νλκ²μΌλ‘ μ°λ¦¬λ Stirngμμ lvalueλ‘μ μ΄λ² μ°μ°μ΄ μνλλ€λ κ²μ μμμλ€. κ·Έλμ μ°λ¦¬λ λ¬Έμμ΄ ν΄λμ€κ° μ΄λ²μλ lvalueμ μλ§λ λμμ ν΄μΌ νλ€λ κ²°λ‘ μ μ»λλ€.
~cpp s2[5] = 'x';
λΉμ·νκ² λ€μκ³Ό κ°μ ꡬ문μ 보면
μ΄κ²μ λκ°μ CharProxyλ₯Ό μν΄μ ν λΉ μ°μ°μκ° λμνκ³ , νλλ charμΌλ‘ μμμ λ³ν, λ νλλ CharProxyκ°μ²΄μ ν λΉ μ°μ°μλ₯Ό μ¬μ©νλ κ²
μΌλ‘ λμ lvalueμ rvalueλ₯Ό ꡬλΆνκ³ μ¬λ°λ₯΄κ² μ¬μ©νκ² λλ€.
μ, μ¬κΈ° κ·ΈλΌ Stringμ operator[]μ λν μλ‘μ΄ κ΅¬ν μ½λκ° μλ€.
κ° ν¨μλ λ¬Έμ μꡬμμ CharProxy κ°μ²΄λ₯Ό λ§λ€μ΄μ λ°ννλ€. λ¬Έμμ΄μ μ€μ€λ‘λ μ무 μΌμ νμ§ λͺ»νλ€. μ°λ¦¬λ κ·Έλ¬ν λμμ μ½κΈ°μ μ°κΈ°μ μ κ·Όμ μμμμλ κΉμ§ μ§μ°μν€λλ‘ λ§λ€μ΄μΌ νλ€.
~cpp s1[3] = s2[8];
μΌλ‘ λμ lvalueμ rvalueλ₯Ό ꡬλΆνκ³ μ¬λ°λ₯΄κ² μ¬μ©νκ² λλ€.
μ, μ¬κΈ° κ·ΈλΌ Stringμ operator[]μ λν μλ‘μ΄ κ΅¬ν μ½λκ° μλ€.
~cpp const String::CharProxy String::operator[](int index) const { return CharProxy(const_cast<String&>(*this), index); } String::CharProxy String::operator[](int index) { return CharProxy(*this, index); }
const λ²μ μ operator[] λ const proxy κ°μ²΄λ₯Ό λ°νν΄μΌ νλ κ²μ 보μ. CharProxy::operator=μ const λ©€λ² ν¨μκ° μ΄λκΈ° λλ¬Έμ ν λΉ(assignment)μ λͺ©νκ° λμ§ μλλ€. κ·Έλ¬λ―λ‘, proxyλ const λ²μ μ operator[]λ, lvalueλ‘μμ λ¬Έμμ΄μ μ¬μ©μ κ³ λ €νμ§ μμλ λλ€. κ°λ¨ν, const λ²μ μ operator[]μμλ μ νν λμκ°λ€λ μ΄μΌκΈ°μ΄λ€.
μ΄λ²μλ CharProxyλ₯Ό λ§λ€λ constλ²μ μ operator[]μμ const_cast(Item 2μ°Έκ³ )λ₯Ό μ¬μ©ν΄μ *thisλ₯Ό λκΈ°λκ±Έ μ£Όλͺ©νμ.μ κ²μ CharProxyμμ±μμ 쑰건μ λΆν©νκΈ° μν μνμΌλ‘, non-const Stringλ§ μΈμλ‘ λ°κΈ°μν΄μ νλ³νμ μννλ€. νλ³νμ 보ν΅μ κ·μ°λ€. κ·Έλ μ§λ§ μ΄λ¬ν κ²½μ°μ CharProxy κ°μ²΄λ κ·Έκ² μμ²΄κ° constμ΄κΈ° λλ¬Έμ Stringκ° ν¬ν¨νκ³ μλ proxyκ° μ°Έμ‘°νλ Stringμ μμ λμ΄μ§λ κ±±μ μ΄ μμ κ²μ΄λ€.
operator[]μ μν΄ λ°νλλ κ° proxyλ ννμ μνμ¬ λ¬Έμλ‘μ νμν μΈλ±μ€μ κΈμ μ 보λ₯Ό μλ‘νκ³ μλ€.
rvalueλ‘μ proxyμ νλ³νμ κ³§λ°λ‘ μΌμ΄ λλ€. μ¦, λ¨μ§ proxyμμ νλ³νμΌλ‘ ν΄λΉνλ μνλ§ ν΄μ£Όλ©΄ λλ€.
λ§μ½ Stringκ°μ²΄μ κ΄κ³λ₯Ό μ½μ΄ λ²λ Έλ€λ©΄, value λ©€λ²μ data λ©€λ²μμ κ΄κ³μ λνμ¬ Itmem 29λ₯Ό λ³΄κ³ κΈ°μ΅ν΄λΌ. μ΄ ν¨μλ λ¬Έμλ₯Ό κ°μΌλ‘(by-value)λ‘ μ λ¬νλ€. κ·Έλ¦¬κ³ C++μ κ·Έλ¬ν κ°μΌλ‘(by-value) μ λ¬μ λ°ν κ°μΌλ‘λ§ λ°ν κ°μ μ¬μ©νλλ‘ μ ννκΈ° λλ¬Έμ λ€μκ³Ό κ°μ νλ³ν ν¨μλ μ€μ§ rvalueλλ§ μ ν¨νλ€.
~cpp String::CharProxy::CharProxy(String& str, int index) : theString(str), charIndex(index) {}
~cpp String::CharProxy::operator char() const { return theString.value->data[charIndex]; }
κ·Έλμ CharProxyμ ν λΉ(assignment) μ°μ°μ ꡬνμΌλ‘ lvalueμ ν΄λΉνλ μμ
λ§ κ°λ₯νκ² κ΅¬νν μ μλ€. μ΄μ CharProxyμ ν λΉ μ°μ°μλ₯Ό λ€μκ³Ό κ°μ΄ ꡬννλ€.
Item 29μ λμμλ, non-const String::operator[]κ³Ό λΉκ΅ν΄λ³΄λ©΄ μΈμμ μΈ λλμ΄ μ¬κ²μ΄λ€. μ΄κ²μ μμΈ‘ν μ μλ€. Item29μμλ μ΄λ¬ν μ°κΈ°μ μ½κΈ°λ₯Ό ꡬλΆνμ§ λͺ»ν΄μ 무쑰건 non-const operator[]λ₯Ό μ°κΈ°λ‘ μ·¨κΈνλ€. κ·Έλ¦¬κ³ , CharProxyλ Stringμ λν μμ λ‘μ΄ μ κ·Όμ μν΄ friendλ‘ μ μΈνκΈ°μ λ¬Έμκ°μ λ³΅μ¬ κ³Όμ μ μνμ΄ κ°λ₯νλ€.
~cpp String::CharProxy& String::CharProxy::operator=(const CharProxy& rhs) { // λ§μ½ λ¬Έμμ΄μ΄ λ€λ₯Έ Stringκ°μ²΄μ κ°μ 곡μ κ° κ°λ₯ν κ²½μ° if (theString.value->isShared()) { theString.value = new StringValue(theString.value->data); } // λ¬Έμ κ°μ λ³΅μ¬ κ³Όμ theString.value->data[charIndex] = rhs.theString.value->data[rhs.charIndex]; return *this; }
μ΄μ λλ¨Έμ§ μ§μ λ¬Έμμ΄μ΄ μ
λ ₯λ λλ₯Ό ꡬννλ€.
Software Engineerμ μννλ μ
μ₯μ΄λΌλ©΄ λ¬Όλ‘ μ΄μ κ°μ΄ CharProxyλ₯Ό ν΅ν΄μ μ½κΈ°μ μ°κΈ°λ₯Ό ꡬλΆν΄μ, 볡μ¬μ ν΄λΉνλ μ½λλ₯Ό μμ ν΄μΌ νλ€.νμ§λ§ μ΄κ²μ λν κ²°μ μ μκ°ν΄ 보μ.
~cpp The second CharProxy assignment operator is almost identical: Β€ Item M30, P58 String::CharProxy& String::CharProxy::operator=(char c) { if (theString.value->isShared()) { theString.value = new StringValue(theString.value->data); } theString.value->data[charIndex] = c; return *this; }
2.3. Limitations : μ ν ¶
proxy ν΄λμ€μ μ¬μ©μ operator[] μ¬μ©μ lvalueμ rvalueμ ꡬλΆμ λͺ
λ£νκ² νλ€. κ·Έλ μ§λ§ 무μν μ μλ κ²°μ μ κ°μ§κ³ μλ€. proxyκ°μ²΄λ κ·Έλ€μ΄ λͺ©ννλ κ°μ²΄λ₯Ό μμ ν κ΅μ²΄νλ κ²μ΄ λͺ©νμ§λ§ μ λ§ μ΄λ ΅λ€. μ¬κΈ°μμ λ¬Έμμ²λΌ, lvalueμ rvalueμ λͺ©μ λΏ μλλΌ. λ€λ₯Έ λ°©λ²μΌλ‘ κ°μ²΄λ μ κ·Όλ μ μλ€.
Item 29μ μΈκΈλ 곡μ νλκ·Έλ₯Ό λν StringValueκ°μ²΄μ κ΄ν΄μ λ€μ μκ°ν΄ 보μ. λ§μ½ String::operator[] κ° char&λμ μ CharProxyλ₯Ό λ°ννλ€λ©΄ μ΄λ¬ν κ²½μ°λ λμ΄μ μ»΄νμΌ ν μκ° μλ€.
s11μ ννμ CharProxyλ₯Ό λ°ννκΈ° λλ¬Έμ, λλ²μ§Έμμ μ€λ₯Έμͺ½μ μλ―Έλ CharProxy*λ₯Ό λ°ννλ κ²μ΄λ€. νμ§λ§ CharProxy*λ₯Ό char*λ‘ λ°κΎΈλ νλ³νμ νμ©λμ§ μκΈ°λλ¬Έμ pμ μ΄κΈ°νμμ μ»΄νμΌλ¬λ μλ¬λ₯Ό λΈλ€. μΌλ°μ μΌλ‘ proxyμ μ£Όμλ μ€μ κ°μ²΄λ³΄λ€ λ€λ₯Έ ν¬μΈν° νμ
μ κ°μ§λ€.
~cpp String s1 = "Hello"; char *p = &s1[1]; // μλ¬!
μ΄λ¬ν λ¬Έμ λ₯Ό μ κ±°νκΈ° μνμ¬ μ£Όμμ κ΄ν μ°μ°μλ₯Ό CharProxy ν΄λμ€μ μ€λ²λ‘λ(overload)νλ€.
μ΄ ν¨μλ ꡬννκΈ° μ½λ€. const ν¨μλ λ¨μ§ const λ²μ μ λ¬Έμμ ν¬μΈν°λ₯Ό νλ‘μ ν΄λμ€λ‘ μ λ¬νλ©΄ λλ€.
non-const ν¨μμ κ²½μ° μ’λ μ κ²½μΈκ²μ΄ λ§μλ°, λ°νλλ ν¬μΈν°μ λ¬Έμκ° μμ κ°λ₯μ±μ΄ μκΈ° λλ¬Έμ΄λ€. μ΄λ¬ν κ²½μ°λ Item 29μμ λ€λ£¨μλ non-const λ²μ μ String::operator[]μ λͺ¨μ΅κ³Ό λΉμ·νλ€.κ·Έλ¦¬κ³ κ΅¬ν μμ λΉμ·νλ€.
μ΄ μ½λλ CharProxyμ λ€λ₯Έ λ©€λ² ν¨μλ€κ³Ό κ°μ΄ νλ²νλ€.
~cpp class String { public: class CharProxy { public: ... char * operator&(); const char * operator&() const; ... }; ... };
~cpp const char * String::CharProxy::operator&() const { return &(theString.value->data[charIndex]); }
~cpp char * String::CharProxy::operator&() { // λ€λ₯Έ κ°μ²΄μ μ 보λ₯Ό 곡μ ν λλ μ μλ£λ₯Ό λ§λ λ€. if (theString.value->isShared()) { theString.value = new StringValue(theString.value->data); } // μ΄μ μ΄ ν¨μκ° λ°ννλ κ°μ²΄λ₯Ό ν΅νμ¬ μμ ν μ μλ€. κ·Έλ¬λ―λ‘ // 곡μ λͺ»νλλ‘ λ§λλ€. theString.value->markUnshareable(); return &(theString.value->data[charIndex]); }
λλ²μ§Έμ κ²°κ³Ό, CharProxyκ° λ€λ₯Έμ μ lvalueμ rvalueμ ꡬλΆμ μν΄ operator[]κ° μ μ©λ νλ‘μ ν΄λμ€λ₯Ό μ¬μ©νλ, μ°Έμ‘°μΈκΈ° λ°°μ΄ ν
νλ¦Ώμ΄λΌλ©΄, νμ°ν λλ¬λλ κ²μ΄λ€.
μ΄λ κ² κ΅¬νλ λ°°μ΄μ μ΄λ»κ² μ¬μ©νλκ° λ³΄μ.
μμλλ λλ‘ operator[]μ λͺ©νμΈ κ°λ¨ν ν λΉ(assignment)μ μ±κ³΅νμ§λ§, left-handμ operator[]μμ operator+=μ΄λ operator-=λ₯Ό νΈμΆνλ건 μ€ν¨νλ€. μλνλ©΄ operator[]κ° λ°ννλ κ²μ νλ‘μ κ°μ²΄ μ΄κΈ° λλ¬Έμ΄λ€. λΉμ·ν κ²½μ°μ μ‘΄μ¬νλ λͺ¨λ μ°μ°μκ° μ€ν¨νλ€. operator*=, operator/=, operator<<=, operator-= λ± λ§μ΄λ€. λ§μ½ μ΄λ° μνμ μνλ€λ©΄ μ΄λ¬ν ν¨μλ₯Ό λͺ¨λ μ μΈν΄μ£Όμ΄μΌ νλλ°, μ΄λ λ무 μΌμ΄ λ§λ€ κ·Έλ¦¬κ³ μλ§ μνμ§λ μμ κ²μ΄λ€. μΆκ°νλ€ μΆκ°νμ§ μμλ€ λλ€ κ΄΄λ‘μ΄ μΌμ΄λ€.
~cpp template<class T> // νλ‘μλ₯Ό μ¬μ©νλ class Array { // μ°Έμ‘°μΈκΈ° μ μ© λ°°μ΄ public: class Proxy { public: Proxy(Array<T>& array, int index); Proxy& operator=(const T& rhs); operator T() const; ... }; const Proxy operator[](int index) const; Proxy operator[](int index); ... };
~cpp Array<int> intArray; ... intArray[5] = 22; // μ³λ€. intArray[5] += 5; // μλ¬! ++intArray[5]; // μλ¬!
κ΄κ³μλ λ¬Έμ λ‘ νλ‘μλ₯Ό ν΅ν μ€μ κ²μ²΄μ νΈμΆμμ μΌμ΄λ μ μλλ°, ν μ μλκ²μ κ΄ν λͺ¨νΈμ±μ΄λ€. μλ₯Όλ€μ΄μ, μ 리μ λ°°μ΄μ μ°Έμ‘°μΈκΈ°λ‘ ꡬννλ€κ³ ν΄λ³΄μ. μ΄κ²μ Rational ν΄λμ€λ‘ μ μνκ³ Array ν
νλ¦Ώμ μ¬μ©νλ€. μ½λλ λ€μκ³Ό κ°λ€.
μ΄λ μμΈ‘ν μ μλ λ°°μ΄μ μ¬μ©μ΄λ€. νμ§λ§ νμ©λμ§ μλλ€.
μ΄λ¬ν μ΄λ €μμ μΆ©λΆν μμλλ€. operator[]κ° λ°ννλ μ 리μμ κ΄ν νλ‘μμ΄μ§ μ§μ§ Rationalκ°μ²΄κ° μλλ€. numeratorκ³Ό denominator λ©€λ² ν¨μλ Rationalμν΄μλ§ μ‘΄μ¬νμ§ νλ‘μλ₯Ό μν΄μλ μ‘΄μ¬νμ§ μλλ€. κ·Έλ¬λ―λ‘ μ»΄νμΌλ¬κ° μ΄μ λν μνμ λͺ»νλ€. νλ‘μλ₯Ό λ§λλκ²μ κ·Έλ€μ΄ μλ―Ένλ κ°μ²΄μ λΉμ·νκ±°μ§ μμ ν λμΌν κ°μ²΄μ κΈ°λ₯μ μ 곡ν μ μλ€.
~cpp class Rational { public: Rational(int numerator = 0, int denominator = 1); int numerator() const; int denominator() const; ... }; Array<Rational> array;
~cpp cout << array[4].numerator(); // μλ¬! int denom = array[22].denominator(); // μλ¬!
μμ§λ νλ‘μκ° μ§μ§ κ°μ²΄λ₯Ό κ΅μ²΄νκΈ° νλ λ¬Έμ λ λ¨μ μλ€. λ€μκ³Ό κ°μ΄ referenceλ‘ λκΈΈλ μ‘°μ°¨ λ§μ΄λ€.
String::operator[]λ CharProxyλ₯Ό λ°ννμ§λ§ swapκ° μνλ κ²μ char&μ΄λ€. CharProxyλ μλ§ μμμ (implicit) νλ³νμΌλ‘ charλ‘ λ³νν κ²μ΄κ³ char&λ‘λ λ³νμ΄ νμ μλ€. κ°λ€κ° νλ³νλ charμ swapλ΄λΆμμ μνμ μμ©μ΄ μλ€. μλνλ©΄, charμ μμ κ°μ²΄μ΄κΈ° λλ¬Έμ΄λ€. μ΄μ λνκ²μ Item 19μ μμΈν μΈκΈλμ΄ μλ€.
~cpp void swap(char& a, char& b); // a μ bμ κ°μ λ°κΎΌλ€. String s = "+C+"; // μꡬ, μ΄κ±° μ΄ λ¬Έμμ΄μ "C++" μΌν λ°. swap(s[0], s[1]); // κ·Έκ²μ κ³ μΉ λ €κ³ νλ€.
λ§μ§λ§ νλ‘μκ° μ€ν¨νλ μ§μ§ κ°μ²΄λ₯Ό κ΅μ²΄νμ§ λͺ»νλ μν©μ μμμ (implicit) νλ³νμμ κΈ°μΈνλ€. νλ‘μ κ°μ²΄λ μμμ (implicit)μΌλ‘ μ§μ§ κ°μ²΄λ‘ νλ³νν λ user-defined νλ³ν ν¨μκ° λΆλ¦°λ€. μλ₯Όλ€μ΄μ CharProxyλ charλ‘ operator charμ νΈμΆν΄μ λ³ννλ€. Item 5μ μ€λͺ
μ 보면 μ»΄νμΌλ¬λ user-defined νλ³ν ν¨μλ₯Ό λ°μνλ μΈμλ‘μ νμμ±μ΄ μλ λΆλΆμμ ν΄λΉ μ°μ°μ νΈμΆνλ€κ³ νλ€. κ²°κ΅ ν¨μ νΈμΆμ νλ‘μκ° μ λ¬λ λ μ€ν¨νλ©΄ μ€μ κ°μ²΄λ₯Ό λκΈ°λ κ²μ μ±κ³΅μμΌμ κ°λ₯ν κ²μ΄λ€. μλ₯Όλ€μ΄μ TVStation리νλ ν΄λμ€μ watchTV ν¨μκ° μλ€κ³ νλ€λ©΄:
μμμ μνμ μν΄μ μ°λ¦¬λ λ€μκ³Ό κ°μ΄ μνν μ μλ€.
νμ§λ§ νλ‘μ μ¬μ©, μ°Έμ‘°μΈκΈ° μ μ© λ°°μ΄μ μ¬μ©νλ€λ©΄
μ΄ λ¬Έμ λ μμμ νλ³νμ΄ μ£Όλ λ νλμ λ¬Έμ μ΄λ€. μ΄κ²μ ν΄κ²°νκΈ°λ μ΄λ ΅λ€. μ¬μ€ TVStationμ μμ±μλ₯Ό explicitλ‘ μ μΈνλ κ²μ΄ λ μ’μ λμμΈμΌ κ²μ΄λ€. κ·Έλ λ€λ©΄ watchTVμμ μ»΄νμΌμ΄ μ€ν¨νλ€. explicitμ κ΄ν μμΈν μ€λͺ
μ Item 5λ₯Ό μ°Έκ³ νλΌ
~cpp class TVStation { public: TVStation(int channel); ... }; void watchTV(const TVStation& station, float hoursToWatch);
~cpp watchTV(10, 2.5); // 10λ² λ³Έλ€. 2.5μκ° λ³Έλ€.
~cpp Array<int> intArray; intArray[4] = 10; watchTV(intArray[4], 2.5);
2.4. Evaluation : νκ° ¶
Proxyν΄λμ€λ ꡬννκΈ° μ΄λ €μ΄ μ΄λ€ μν©μμ ν΄κ²°μ±
μ΄ λ μ μλ€. λ€μ°¨μ λ°°μ΄μ΄ 첫λ²μ§Έ, lvaue/rvalueκ° λλ²μ§Έ , μμμ νλ³ν κΈμ§κ° μΈλ²μ§Έ μ΄λ€.
λ Proxy ν΄λμ€λ λ¨μ λ λ§μ΄λ κ°μ§κ³ μλ€. ν¨μκ° κ°μ λ°νν λ νλ‘μ κ°μ²΄λ€μ μμ μΈμ(temporaries:Item 19μ°Έκ³ )λ‘ μ λ¬λλ€. κ·Έλμ κ·Έλ€μ μμ±, μμ λλ€. μ΄κ²μ 곡μ§κ° μλλ€. μ½κΈ°μ μ°κΈ°μ κ²½μ°λ₯Ό κ°λ¦¬κΈ° μν μ‘°μΉλ, μμμΈμλ₯Ό λ§λ€κΈ° λλ¬Έμ λΉμ©μ΄ λ°μνλ€. νλ‘μ ν΄λμ€κ° μμ΄μ μννΈμ¨μ΄ ꡬ쑰λ 볡μ‘ν΄ μ§λ€. λ μ΄λ €μ΄ λμμΈ, ꡬν, μ΄ν΄ κ·Έλ¦¬κ³ μ μ§ λ³΄μ..
λ§μ§λ§μΌλ‘ μ§μ§ κ°μ²΄μ λν μΌμ λνμ μ’
μ’
λ¬Έλ²μ μ νμ κ°μ§κ³ μ¨λ€. μλνλ©΄ νλ‘μ κ°μ²΄κ° μ€μ κ°μ²΄λ₯Ό μμ ν κ΅μ²΄ν λ§νΌ λ₯λ ₯μ κ°μ§μ μκΈ° λλ¬Έμ΄λ€. λλ‘ νλ‘μλ μμ€ν
μ λμμΈμ λ λμ μ νμ κ°μ§κ³ μ¨λ€. νμ§λ§ λ§μ κ²½μ° νλ‘μμ μ‘΄μ λ ν΄λΌμ΄μΈνΈμκ² κ·Έ μνμ μμνκ² νλ κ²½μ°λ κ±°μ μλ€. μλ₯Ό λ€μ΄μ ν΄λΌμ΄μΈνΈλ μ΄μ°¨μ λ°°μ΄μ μμ μμ Array1D κ°μ²΄μ μ£Όμλ₯Ό μνλ ν΄λΌμ΄μΈνΈλ κ±°μ μλ€. κ·Έλ¦¬κ³ ArrayIndexκ°μ²΄(Item 5μ°Έκ³ )λ μμλλ λ€λ₯Έ ννμ ν¨μλ‘ μ λ¬ λ κ²μ΄λ€. λ§μ κ²½μ°μ νλ‘μλ μ§μ§ κ°μ²΄μ μνμ λννλ€. κ·Έλ€μ μ μ©ν λ, μλ¬΄μΌ μλ건 κ±°μ λλΆλΆμ΄λ€.