U E D R , A S I H C RSS

More EffectiveC++/Techniques2of3

1. Item 29: Reference counting

  • Item 29: ฐธกฐ „ธ๊ธฐ

1.1. †Œ๊ฐœ

Reference counting(ด•˜ ฐธกฐ „ธ๊ธฐ, ๋‹จ–ด๊ฐ€ ๊ธธ–ด ˜–ด ˜ผšฉ •˜ง€ •ŠŒ)๋Š” ๊ฐ™€ ๊ฐ’œผ๋กœ ‘œ˜„๋˜๋Š” ˆ˜๋งŽ€ ๊ฐฒด๋“ค„ •˜๋‚˜˜ ๊ฐ’œผ๋กœ ๊ณตœ •ด„œ ‘œ˜„•˜๋Š” ๊ธฐˆ ด๋‹ค. ฐธกฐ „ธ๊ธฐ๋Š” ๋‘๊ฐ€ง€˜ ผ๋ฐ˜ ธ ๋™๊ธฐ๋กœ  œ•ˆ๋˜—ˆ๋Š”๋ฐ, ฒซ๋ฒˆงธ๋กœ heap ๊ฐฒด๋“ค„ ˆ˜šฉ•˜๊ธฐ œ„•œ ๊ธฐ๋ก˜ ๋‹จˆœ™”๋ฅผ œ„•ด„œ ด๋‹ค. •˜๋‚˜˜ ๊ฐฒด๊ฐ€ ๋งŒ๋“ค–ด ง€๋Š”๋ฐ, new๊ฐ€ ˜ธถœ๋˜๊ณ  ด๊ฒƒ€ delete๊ฐ€ ๋ถˆ๋ฆฌ๊ธฐ  „๊นŒง€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ฐจง€•œ๋‹ค. ฐธกฐ „ธ๊ธฐ๋Š” ๊ฐ™€ ž๋ฃŒ๋“ค˜ ค‘๋ณต๋œ ๊ฐฒด๋“ค„ •˜๋‚˜๋กœ ๊ณตœ •˜—ฌ, new™€ delete๋ฅผ ˜ธถœ•˜๋Š” ŠคŠธ๋ ˆŠค๋ฅผ „ด๊ณ , ๋ฉ”๋ชจ๋ฆฌ— ๊ฐฒด๊ฐ€ ๋“๋ก๋˜–ด œ ง€๋˜๋Š” ๋น„šฉ๋„ „ผˆ˜ žˆ๋‹ค. ๋‘๋ฒˆงธ˜ ๋™๊ธฐ๋Š” ๊ทธ๋ƒฅ ผ๋ฐ˜ ธ ƒ๊ฐ—„œ ๋‚˜™”๋‹ค. ค‘๋ณต๋œ ž๋ฃŒ๋ฅผ —ฌ๋Ÿฌ ๊ฐฒด๊ฐ€ ๊ณตœ •˜—ฌ, ๋น„šฉ  ˆ•ฝ ๋ฟ•„๋‹ˆ๋ผ, ƒ„, ŒŒ๊ดด˜ ๊ณผ •˜ ƒ๋žตœผ๋กœ ”„๋กœ๊ทธ๋žจ ˆ˜–‰ †๋„๊นŒง€ ๋†’ด๊ณ ž •˜๋Š” ๋ชฉ ด๋‹ค.

ด๋Ÿฐ ๊ฐ„๋‹จ•œ ƒ๊ฐ๋“ค˜  šฉ„ œ„•ด„œ๋Š” ๋งŽด “ฐด๋Š” ž๋ฃŒ˜•ƒœ๋ฅผ ฐพ•„ ˜ˆ œ‚ผ•„ ๋ณด—ฌฃผ๋Š” ๊ฒƒด ด•ด— ๋„›€ด ๋„๋ฆฌ๊ฒƒด๋‹ค. ด๋Ÿฐ ๋ฉด—„œ ๋‹คŒ˜ ˜ˆ๋Š”  •ฉ•  ๊ฒƒด๋‹ค.

~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";
a~e๊นŒง€ ๋ชจ๋‘ "Hello"๋ผ๋Š” ๊ฐ™€ ๊ฐ’„ ๊ฐ€ง€๊ณ  žˆ๋Š” ๋‹ค๋ฅธ ๊ฐฒดด๋‹ค. ด ด๋ž˜Šค๋Š” ฐธกฐ „ธ๊ธฐ๊ฐ€  šฉ๋˜ง€ •Š•˜๊ธฐ ๋•Œ๋ฌธ— ๋ชจ๋‘ ๊ฐ๊ฐ˜ ๊ฐ’„ ๊ฐ€ง€๊ณ  žˆ๋‹ค. ๋ฌธž—ด˜ • ๋‹น(assignment) —ฐ‚ฐž๋Š” •„๋งˆ ๋‹คŒ๊ณผ ๊ฐ™ด ๊ตฌ˜„๋˜–ด žˆ„ ๊ฒƒด๋‹ค.

~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)— œ„น˜•œ๋‹ค.

ง€๊ธˆ๊นŒง€ ๋ง•œ ‚ฌ•ญ˜ ๊ธฐ๋ณธ€ ๋‹คŒ๊ณผ ๊ฐ™๋‹ค.

~cpp 
class String {
public:
    ...                         // String member๋“ค œ„น˜
private:
    struct StringValue { ... }; // ฐธกฐ๋ฅผ „ธ๋Š” ธž™€, String˜ ๊ฐ’„  €žฅ.
    StringValue *value;         // œ„˜ ๊ตฌกฐฒด˜ ๊ฐ’
};
๋ฌผ๋ก  ด˜ ด๋ฆ„€ String๊ณผ ๋‹ค๋ฅธ ด๋ฆ„„ ๋งค๊ฒจ•ผ •˜๊ฒ ง€๋งŒ,(•„๋งˆ RCString •๋„?) •˜ง€๋งŒ Stringžฒด๋ฅผ ๊ตฌ˜„•œ๋‹ค๋Š” ˜๋ฏธ๋กœ ๊ทธ๋ƒฅ ด๋ฆ„€ œ ง€•˜๊ณ , •žœผ๋กœ ๋ง•  ฐธกฐ„ธ๊ธฐ๋ฅผ  šฉ‹œ‚จ 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;     // ŠคŠธ๋ง ‚ญ œ
}
ด๊ฒƒœผ๋กœ StringValue˜ ๊ตฌ˜„€ ผ๋‹จ ๋ด๋‹ค. ด๋ฅผ ‚ฌšฉ•˜๋Š” String ๊ฐฒด˜ ๊ตฌ˜„— ๋“ค–ด๊ฐ€•ผ •œ๋‹ค.

๋จผ € ƒ„ž๋ฅผ ๊ตฌ˜„•œ๋‹ค.

~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ธ ๊ฒฝšฐ ๋”ดƒ ‚ฌšฉ•˜๋Š” ๊ฐฒด๊ฐ€ —†œผ๋ฏ€๋กœ ŒŒ๊ดด•˜๋„๋ก ๊ตฌ„•œ๋‹ค.

~cpp 
class String {
public:
    ~String();
    ...
};
String::~String()
{
    if (--value->refCount == 0) delete value;   // ฐธกฐ นดšด„ฐ๊ฐ€ 1ธ ƒƒœ
}
ŒŒ๊ดดž˜ šจœจ„ ๋น„๊ต•ด๋„ —ญ‹œ, ๋งˆฐฌ๊ฐ€ง€ด๋‹ค. delete๊ฐ€ ๋ถˆ๋ฆฌ๋Š” ‹œ € •ด๋‹น ๊ฐฒด๊ฐ€ ๋” ดƒ •„š” —†„๋•Œ๋งŒ  œ๊•˜๋Š” ๊ฒƒด๊ธฐ ๋•Œ๋ฌธ— ๋น„šฉ„ •„๋‚„ˆ˜ žˆ๋‹ค.

๋‹คŒ— ๊ตฌ˜„•ด•ผ•  ‚ฌ•ญ€ • ๋‹น(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) —ฐ‚ฐž๋“ค "[]" ด๋…€„๋“ค— ๊ด€•ด„œ ƒ๊ฐ•ด ๋ณดž. ด๋ž˜Šค˜ „ –ธ€ ๋‹คŒ๊ณผ ๊ฐ™๋‹ค.

~cpp 
class String {
public:
    const char& operator[](int index) const;    // const String— ๋Œ€•˜—ฌ

    char& operator[](int index);                // non-const String— ๋Œ€•˜—ฌ
    ...
};
const String— ๋Œ€•œ ๊ฐ’„ ฃผ๋Š” ๊ฒƒ€ •„๋ž˜™€ ๊ฐ™ด ๊ฐ„๋‹จžˆ •ด๊ฒฐ๋œ๋‹ค. ๋‚ด๋ถ€ ๊ฐ’ด •„๋ฌด๋Ÿฐ ˜–ฅ„ ๋ฐ›„ ๊ฒƒด —†„ ๊ฒฝšฐด๊ธฐ ๋–„๋ฌธด๋‹ค.

~cpp 
const char& String::operator[](int index) const
{
  return value->data[index];
}
(ด •จˆ˜๋Š” ›๋ž˜˜ C++—„œ ๋ฐฐ—ด˜ ‚ฌšฉ ๊ฐœ๋…๊ณผ ๊ฐ™ด, index˜ œ šจ„„  ๊ฒ€•˜ง€ •Š๋Š”๋‹ค. ด— ๋Œ€•œ ๊ฐ€€ ฐธกฐ „ธ๊ธฐ˜ ฃผ œ— ๋–จ–ด ธ žˆ๊ณ , ถ”๊ฐ€•˜๋Š” ๊ฒƒ๋„ ๊ทธ๋ฆฌ –ด๋ คšดผด •„๋‹ˆ๋ผ ผ๋‹จ€  œ™ธ•œ๋‹ค.)

•˜ง€๋งŒ non-const˜ operator[]๋Š” ด๊ฒƒ(const operator[])™€ ™„ „žˆ ๋‹ค๋ฅธ ƒ™ฉด ๋œ๋‹ค. ดœ ๋Š” non-const operator[]๋Š” StringValue๊ฐ€ ๊ฐ€๋ฆฌ‚ค๊ณ  žˆ๋Š” ๊ฐ’„ ๋ณ€๊ฒฝ• ˆ˜ žˆ๋Š” ๊ถŒ•œ„ ๋‚ดฃผ๊ธฐ ๋•Œ๋ฌธด๋‹ค. ฆ‰, non-const operator[]๋Š” ž๋ฃŒ˜ ฝ๊ธฐ(Read)™€ “ฐ๊ธฐ(Write)๋ฅผ ๋‹ค —ˆšฉ•œ๋‹ค.

~cpp 
String s;
...
cout << s[3];       // ด๊ฝ๊ธฐ(Read)
s[5] = 'x';         // ด๊“ฐ๊ธฐ(Write)

ฐธกฐ „ธ๊ธฐ๊ฐ€  šฉ๋œ String€ ˆ˜ •• ๋•Œ กฐ‹ฌ•˜๊ฒŒ •ด•ผ ๋œ๋‹ค. ๊ทธ๋ž˜„œ ผ๋‹จ •ˆ „•œ non-const operator[]๋ฅผ ˆ˜–‰•˜๊ธฐ œ„•˜—ฌ •„˜ˆ operator[]๋ฅผ ˆ˜–‰• ๋•Œ ๋งˆ๋‹ค ƒˆ๋กœšด ๊ฐฒด๋ฅผ ƒ„•ด ๋ฒ„๋ฆฌ๋Š” ๊ฒƒด๋‹ค. ๊ทธ๋ž˜„œ ๋งŒ๋“  ๊ฒƒด ๋‹คŒ๊ณผ ๊ฐ™€ ๋ฐฉ๋ฒ•œผ๋กœ •˜๊ณ , „ค๋ช…€ ฃผ„— ๋” ž„žˆ

~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๋ฅผ ๊ตฌ˜„• ๋•Œ  •™•„๊ณผ šจœจ„, ๋‘˜๋‹ค ๋งŒ  ‹œ‚ค๋Š” Žธด๋‹ค. •˜ง€๋งŒ •ญƒ๋”ฐ๋ผ๋‹ค๋‹ˆ๋Š”๋ฌด๋„บ๊ฐ€ žˆ๋Š”๋ฐ, ๋‹คŒ ฝ”๋“œ๋ฅผ ƒ๊ฐ•ด ๋ณดž.

~cpp 
String s1 = "Hello";
char *p = &s1[1];
ด๋ฅผ ๋Œ€๊ฐ• ๊ทธ๋ฆผ„ ๋‚˜ƒ€๋‚ด ๋ณด๋ฉด p๊ฐ€ Hello˜ e๋ฅผ ๊ฐ€๋ฆฌ‚ค๋Š” ด •๋„˜ ๋А๋‚Œผ ๊ฒƒด๋‹ค.


๊ทธ๋Ÿฌ๋ฉด ด๋ฒˆ—๋Š” —ฌ๊ธฐ— •œ„๋งŒ ๋ง๋ถ™—ฌ ๋ณธ๋‹ค.

~cpp 
String s2 = s1;
String ๋ณต‚ฌ ƒ„ž๊ฐ€ •„๋งˆ s2๊ฐ€ s1˜ StringValue๋ฅผ ๊ณตœ •˜๊ฒŒ ๋งŒ๋“ค๊ฒƒด๋‹ค. ๊ทธ๋ž˜„œ ๋‹นŒ๊ณผ ๊ฐ™€ ๊ทธ๋ฆผœผ๋กœ ‘œ˜„๋  ๊ฒƒด๋‹ค.


๊ทธ๋ž˜„œ ๋‹คŒ๊ณผ ๊ฐ™€ ๊ตฌ๋ฌธ„ ‹ค–‰•œ๋‹ค๋ฉด

~cpp 
p = 'x';                     // ด ๊ฒƒ€ s1, s2๋ฅผ ๋ชจ๋‘ ๋ณ€๊ฒฝ!
String˜ ๋ณต‚ฌ ƒ„ž๋Š” ด๋Ÿฌ•œ ƒƒœ๋ฅผ ๊ฐง€•  ๋ฐฉ๋ฒ•ด —†๋‹ค. œ„—„œ ๋ณด๋“ฏด, s2๊ฐ€ ฐธ๊ณ • ˆ˜ žˆ๋Š”  •๋ณด๋Š” ๋ชจ๋‘ s1˜ ๋‚ด๋ถ€— žˆ๋Š”๋ฐ, s1—๊ฒŒ๋Š” non-const operator[]๋ฅผ ˆ˜–‰•˜˜€๋Š”ง€— ๊ด€•œ ๊ธฐ๋ก€ —†๋‹ค.

ด๋Ÿฐ๊ฒƒ„ •ด๊ฒฐ• ˆ˜ žˆ๋Š” ๋ฐฉ๋ฒ•œผ๋กœ๋Š” ตœ†Œ•œ „ธ๊ฐ€ง€๋ฅผ ƒ๊ฐ• ˆ˜ žˆ๋Š”๋ฐ, ฒซ๋ฒˆงธ๋Š” ด๊ฒƒ„ —†๋Š”๊ธ๋กœ ทจ๊ธ‰•˜๊ณ , ๋ฌด‹œ •ด ๋ฒ„๋ฆฌ๋Š” ๊ฒƒด๋‹ค. ด๋Ÿฌ•œ  ‘๊ทผ ๋ฐฉ–ฅ€ ฐธกฐ „ธ๊ธฐ๊ฐ€  šฉ๋˜–ด žˆ๋Š” ด๋ž˜Šค ๋ผด๋ธŒ๋Ÿฌ๋ฆฌ— ƒ๋‹น•œ ๊ดด๋กœ›€„ ๋œ–ด ฃผ๋Š”๊ฒƒด๋‹ค. •˜ง€๋งŒ ด๋Ÿฌ•œ ๋ฌธ œ๋ฅผ ๊ตฌ˜„ƒ—„œ ™„ „žˆ ๋ฌด‹œ• ˆ˜๋Š” —†๋Š” ๋…ธ๋ฆ‡ด๋‹ค. ๋‘๋ฒˆงธ๋กœ ƒ๊ฐ• ˆ˜ žˆ๋Š” ๋ฐฉ๋ฒ•€ ด๋Ÿฌ•œ๊ฒƒ„ •˜ง€ ๋ง๋„๋ก ๋ช…‹œ•˜๋Š” ๊ฒƒธ๋ฐ, —ญ‹œ๋‚˜ ๋ณตžก•˜๋‹ค. „ธ๋ฒˆงธ๋กœ, ๋ญ ๊ฒฐ๊ตญ  œ๊•ผ๋งŒ • ๊ฒƒด๋‹ค. ด๋Ÿฌ•œ ๋ถ„ œ˜  œ๊ฐ๋Š” ๊ทธ๋ฆฌ –ด๋ ตง€๋Š” •Š๋‹ค. ๋ฌธ œ๋Š” šจœจด๋‹ค. ด๋Ÿฐ ค‘๋ณต— ๊ด€๋ จ•œ ๋ฌธ œ๋ฅผ  œ๊•˜๊ธฐ œ„•ด„œ๋Š”, ƒˆ๋กœšด ž๋ฃŒ ๊ตฌกฐ๋ฅผ ๋งŒ๋“ค–ด ๋‚ด•ผ•˜๊ณ , ด๊ฒƒ˜ ˜๋ฏธ๋Š” ๊ฐฒด๊ฐ„— „œ๋กœ ๊ณตœ •˜๋Š” ž๋ฃŒ๊ฐ€ „–ด ๋“ ๋‹ค๋Š” ˜๋ฏธด๋‹ค. ฆ‰, ๋น„šฉด ๋งŽด ๋“ค–ด๊ฐ„๋‹ค. •˜ง€๋งŒ –ดฉ”ˆ˜ —†ง€ •Š„๊นŒ?

๊ฐ„๋‹จ•œ ”Œ๋ž˜๊ทธ •˜๋‚˜๋ฅผ ถ”๊ฐ€•˜๋Š” ๊ฒƒœผ๋กœ ด ๋ฌธ œ๋Š” •ด๊ฒฐ๋œ๋‹ค. ด๋ฒˆ ˆ˜ • ๋ฒ„ „€ ๊ณตœ ˜ —ฌ๋ถ€๋ฅผ —ˆ๋ฝ•˜๋Š” sharable ธž๋ฅผ ๋”•œ ๊ฒƒด๋‹ค. ฝ”๋“œ๋ฅผ ๋ณดž.

~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);
  }
}
๊ทธ๋ฆฌ๊ณ  ด shareableธž๋Š” non-const operator[]๊ฐ€ ˜ธถœ๋ ๋•Œ false๋กœ ๋ณ€๊ฒฝ๋˜–ด„œ ด›„, •ด๋‹น ž๋ฃŒ˜ ๊ณตœ ๋ฅผ ๊ธˆง€•œ๋‹ค.

~cpp 
char& String::operator[](int index)
{
    if (value->refCount > 1) {
        --value->refCount;
        value = new StringValue(value->data);
    }
    value->shareable = false;           // ด œ ž๋ฃŒ˜ ๊ณตœ ๋ฅผ ๊ธˆง€•œ๋‹ค.
    return value->data[index];
}
๋งŒ•ฝ Item 30— –ธ๊ธ‰๋˜๋Š” proxy ด๋ž˜Šค ๋ฐฉ๋ฒ•„ ‚ฌšฉ•ด„œ ฝ๋Š” ž‘—…๊ณผ, “ฐ๋Š” ž‘—…— ๋Œ€•œ ๊ฒƒ„ ๊ตฌ๋ถ„•œ๋‹ค๋ฉด StringValue ๊ฐฒด˜ ˆž๋ฅผ ข€๋” „ผˆ˜ žˆ„ ๊ฒƒด๋‹ค. ๊ทธ๊ด ๋‹คŒ žฅ—„œ ๋ณดž.

1.5. A Reference-Counting Base Class : ฐธกฐ-„ธ๊ธฐ ๊ธฐˆ ด๋ž˜Šค

ฐธกฐ„ธ๊ธฐ๋Š” ๋‹จง€ string˜ ๊ฒฝšฐ—๋งŒ œ šฉ•œ๊ธ๊นŒ? ๋‹ค๋ฅธ ๊ฐฒด —ญ‹œ ฐธกฐ„ธ๊ธฐ๋ฅผ  šฉ•ด„œ ‚ฌšฉ• ˆ˜๋Š” —†„๊นŒ? ƒ๊ฐ•ด ๋ณด๋ฉด ฐธกฐ„ธ๊ธฐ๋ฅผ ๊ตฌ˜„•˜๊ธฐ œ„•ด„œ๋Š” ง€๊ธˆ๊นŒง€˜ –ธ๊ธ‰˜ ๊ธฐ๋Šฅ„ ๋ฌถ–ด„œ žฌ‚ฌšฉ ๊ฐ€๋Šฅ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด ข‹„๊ฒƒ ๊ฐ™€๋ฐ, •œ๋ฒˆ ๋งŒ๋“ค–ด ๋ณด๋„๋ก •˜ž.

 œผ ฒ˜Œ— •ด•ผ • ผ€ ฐธกฐ„ธ๊ธฐ๊ฐ€  šฉ๋œ ๊ฐฒด๋ฅผ œ„•œ (reference-counded object) RCObject๊ฐ™€ ๊ธฐˆ ด๋ž˜Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒด๋‹ค. –ด๋– •œ ด๋ผŠค๋ผ๋„ ด ด๋ž˜Šค๋ฅผ ƒ†๋ฐ›œผ๋ฉด ž๋™ œผ๋กœ ฐธกฐ„ธ๊ธฐ˜ ๊ธฐ๋Šฅด ๊ตฌ˜„๋˜๋Š” ˜•‹„ ๋ฐ”๋ผ๋Š” ๊ฒƒด๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ œ„•ด„œ๋Š” RCObject๊ฐ€ ๊ฐ€ง€๊ณ  žˆ–ด•ผ •˜๋Š” ๋Šฅ๋ ฅ€ นดšด„— ๋Œ€•œ ฆ๊ฐ— ๋Œ€•œ ๋Šฅ๋ ฅผ ๊ฒƒด๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ๋” ดƒ, ‚ฌšฉด •„š” —†๋Š” ‹œ —„œ๋Š” ŒŒ๊ดด๋˜–ด•ผ •œ๊ฒƒด๋‹ค. ๋‹ค‹œ๋ง•ด, ŒŒ๊ดด๋˜๋Š” ‹œ € นดšด„˜ ธž๊ฐ€ 0ด ๋ ๋•Œด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ณตœ  —ˆšฉ ”Œ๋ž˜๊ทธ— ๋Œ€•œ(shareable flag) ๊ด€•œ ๊ฒƒ€, ˜„žฌ๊ฐ€ ๊ณตœ  ๊ฐ€๋Šฅ•œ ƒƒœธง€ ๊ฒ€ฆ•˜๋Š” ๋ฉ”†Œ๋“œ™€, ๊ณตœ ๋ฅผ ๋ฌถ–ด ๋ฒ„๋ฆฌ๋Š” ๋ฉ”†Œ๋“œ, ด๋ ‡๊ฒŒ๋งŒ žˆœผ๋ฉด ๋ ๊ฒƒด๋‹ค. ๊ณตœ ๋ฅผ ‘ผ๋‹ค๋Š” ๊ฒƒ€ ง€๊ธˆ๊นŒง€˜ ƒ๊ฐœผ๋กœ๋Š” ๋ถˆ๊ฐ€๋Šฅ•œ ๊ฒƒด๊ธฐ ๋•Œ๋ฌธด๋‹ค.

ด๋Ÿฌ•œ  •˜๋ฅผ ๋ชจ•„๋ชจ•„ ๋ผˆ๋Œ€๋ฅผ ๋งŒ๋“ค๋ฉด ๋‹คŒ๊ณผ ๊ฐ™๋‹ค.

~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๋Š” ƒ„๋˜๊ณ , ŒŒ๊ดด๋˜–ด ˆˆ˜ žˆ–ด•ผ •œ๋‹ค. ƒˆ๋กœšด ฐธกฐ๊ฐ€ ถ”๊ฐ€๋˜๋ฉด ˜„žฌ˜ ฐธกฐ๋Š”  œ๊ฐ๋˜–ด•ผ •œ๋‹ค. ๊ณตœ  ƒƒœ— ๋Œ€•ด —ฌ๋ถ€๋ฅผ •Œˆ˜ žˆ–ด•ผ •˜๋ฉฐ, disable๋กœ „ •• ˆ˜ žˆ–ด•ผ •œ๋‹ค. ŒŒ๊ดดž— ๋Œ€•œ ‹คˆ˜๋ฅผ ๋ฐฉง€•˜๊ธฐ œ„•˜—ฌ ๋ฒ ดŠค ด๋ž˜Šค๋Š” ŒŒ๊ดดž๋ฅผ ๊ฐ€ƒ •จˆ˜๋กœ„ –ธ•ด•ผ ๋œ๋‹ค. —ฌ๊ธฐ—„œ๋Š” ˆœˆ˜ ๊ฐ€ƒ •จˆ˜(pure virtual function)๋กœ „ –ธ•œ๋‹ค.

๋‹คŒ ฝ”๋“œ๊ฐ€ 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œผ๋กœ „Œ…•œ๋‹ค. ด๊ง๊ด€ ดง€ ๋ชป•˜๊ฒŒ ๋ณดด๋Š”๋ฐ, ™•‹คžˆ ƒˆ๋กœ ๋งŒ๋“ค–ดง€๋Š” RCObject˜ ƒ„ž๋Š” ƒˆ๋กœ ๋งŒ๋“ค–ด„ RCObject๋ฅผ ฐธกฐ•˜๊ณ  žˆ„ ๊ฒƒด๊ธฐ ๋•Œ๋ฌธด๋‹ค. •˜ง€๋งŒ ด๋Ÿฌ•œ ดœ ๋Š”, ƒˆ๋กœšด ๊ฐฒด๊ฐ€ • ๋‹น๋œ ๋’ค— œ ๋„๋œ ด๋ž˜Šค ŠคŠค๋กœ, refCount๋ฅผ ฆ๊ฐ€ ‹œผœฃผ๊ธฐœ„•ด„œ ด๋‹ค. ด๊ฒƒด ‚ฌšฉž—๊ฒŒ ๋” ๋ช…‹œ ธ ฝ”๋“œ๋ฅผ ž‘„•˜๊ฒŒ ๋œ๋‹ค.

˜๋ฌธ ๋‘˜, ๋ณต‚ฌ ƒ„ž๋Š” refCount๋ฅผ •ญƒ 0œผ๋กœ „Œ…•ด ๋ฒ„๋ฆฐ๋‹ค. ‚ฌ‹ค ๋ณต‚ฌ• ๋•Œ๋Š” refCount๋Š” ƒ๊ด€ด —†๋‹ค. ดœ ๋Š” ƒˆ๋กœšด ๊ฐฒด˜ ๊ฐ’ด๋ผ, ด๊ฒƒ€ •ญƒ –ด๋–ค ๊ฐฒด™€๋„ ๊ณตœ •˜๊ณ  žˆง€ •Š๊ธฐ ๋•Œ๋ฌธ— refCount๋ฅผ ˆ๊ธฐ™” ‹œ‚จ๋‹ค.

˜๋ฌธ …‹, • ๋‹น(assignment) —ฐ‚ฐž๋Š” •„๊นŒ ๊ณตœ  ๋ฌธ œ๋ฅผ ๋’คง‘–ด ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ ฒ˜๋Ÿผ ๋ณดธ๋‹ค. •˜ง€๋งŒ ด ๊ฐฒด๋Š” ๊ธฐˆ ด๋ž˜Šคด๋‹ค. –ด๋–ค ƒ™ฉ—„œ ด๋ฅผ œ ๋„•˜๋Š” ๋‹ค๋ฅธ ด๋ž˜Šค๊ฐ€ ๊ณตœ  flag๋ฅผ ๋น„™œ„™” ‹œ‚ค๋Š”ง€ ™•‹  • ˆ˜ —†๊ธฐ ๋•Œ๋ฌธ—, ผ๋‹จ •„๋ฌด๊ฒƒ๋„ •˜ง€ •Š๊ณ , ˜„žฌ˜ ๊ฐฒด๋ฅผ ๋ฐ˜™˜•˜๊ฒŒ •ด ๋‘—ˆ๋‹ค.

๊ณ„† •ด๊น”๋ฆดˆ˜ žˆ๋Š”๋ฐ, ๋‹คŒ๊ณผ ๊ฐ™€ ฝ”๋“œ๋ฅผ ๋ณด๋ฉด

~cpp 
sv1 = sv2;          // –ด๋–ป๊ฒŒ sv1๊ณผ sv2˜ ฐธกฐ นดšด„ฐ๊ฐ€ ˜–ฅ ๋ฐ›„๊นŒ?
ž, RCObject๋Š” ๊ธฐˆ ด๋ž˜Šคด๋ฉฐ, ฐจ›„ ๋ฐด„ฐ๋ฅผ  €žฅ•˜๋Š” ๊ณต๊ฐ„€ RCObject˜ ž‹—๊ฒŒ„œ ๊ตฌ˜„๋˜–ด „๋‹ค. ๊ทธ๋ž˜„œ opreator=€ œ ๋„ ๋œ ด๋ž˜Šค—„œ ›• ๋•Œ ด ฐธกฐ ๊ฐฒด๋ฅผ ๋ฐ”๊พธ๊ธฐ œ„•˜—ฌ, RCObject::operator= ˜•‹œผ๋กœ ๋ถˆ๋Ÿฌ•ผ •œ๋‹ค. ด•˜, ๊˜๋‹ค †ŒŠค žฒด๋ฅผ ด•ด•ด•ผ •œ๋‹ค. •ด๋‹น RCObject๋ฅผ ดšฉ•ด„œ œ ๋„๋œ ด๋ž˜Šค˜ ๋ชจ–‘€ ๋‹คŒ๊ณผ ๊ฐ™œผ๋ฉฐ, ๋ชจ๋“  ฝ”๋“œ๋Š” ๊ตฌ˜„•˜ง€ •Š๊ฒ ง€๋งŒ, ง€๊ธˆ๊นŒง€˜ ๊ฐœ๋…œผ๋กœ ด•ด• ˆ˜ žˆ„ ๊ฒƒด๋‹ค.

~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;
}
ด StringValue๋ฒ„ „€ ด „— ๋ณด๋˜๊ฒƒ๊ณผ ๊˜ ๋™ผ•œ ˜•ƒœ๋ฅผ ๋ณดธ๋‹ค.๋‹จ, refCount๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒƒ๋งŒด RCObject˜ ๋ฉค๋ฒ„ •จˆ˜๋กœ„œ ๋ชจ๋“  ๊ธฐ๋Šฅ„ ›„–‰•˜๋Š” ๊ฒƒด๋‹ค. ด ๊ฒƒ˜ ๋” ๊ตฌฒด ธ ฝ”๋“œ๋Š” ๋‹คŒ žฅ—„œ ๋ณดด๋Š” Šค๋งˆŠธ ฌธ„ฐ๋ฅผ ดšฉ•œ ž๋™ ฐธกฐ นดšดŒ… ๊ธฐ๋Šฅ„ ๋ง๋ถ™ด๋ฉด„œ –ดฐจ”ผ ๋ชจ๋“  ฝ”๋“œ๋ฅผ „œˆ •  ๊ฒƒด๋‹ค.

ด๋ฒˆ ฃผ œ˜ nested class˜ ๋ชจŠต„ ๋ณด๋ฉด ๊ทธ๋ฆฌ ข‹™€ ๋ณดดง€๋Š” •Š„ ๊ฒƒด๋‹ค.ฒ˜Œ—๋Š” ƒ†Œ•˜๊ฒ ง€๋งŒ, ด๋Ÿฌ•œ ๋ฐฉ๋ฒ„€  •๋‹น•œ ๊ฒƒด๋‹ค. nestedด๋ž˜Šค˜ ๋ฐฉ๋ฒ•€ ˆ˜๋งŽ€ ด๋ž˜Šค˜ ข…๋ฅ˜ค‘ ๋‹จง€ •˜๋‚˜ ๋ฟด๋‹ค. ด๊ฒƒ„ Šน๋ณ„žˆ ทจ๊ธ‰•˜ง€๋Š” ๋ง•„๋ผ.

1.6. Automating Reference Count Manipulations : ž๋™ ฐธกฐ „ธ๊ธฐ ๋ฐฉ๋ฒ•

RCObject๋Š” ฐธกฐ นดšด„ฐ๋ฅผ ๋ณด๊ด€•˜๊ณ , นดšด„˜ ฆ๊ฐ„ •ด๋‹น ด๋ž˜Šค˜ ๋ฉค๋ฒ„ •จˆ˜๋กœ ง€›•œ๋‹ค. •˜ง€๋งŒ ด๊œ ๋„๋˜๋Š” ๋‹ค๋ฅธ ด๋ž˜Šค— ˜•˜—ฌ, †ˆ˜ ฝ”๋”ฉด ๋˜–ด•ผ •œ๋‹ค. ฆ‰, œ„˜ ๊ฒฝšฐ๋ผ๋ฉด, StirngValue ด๋ž˜Šค—„œ addReference, removeReference ๋ฅผ ˜ธถœ•˜๋ฉด„œ, ผผด ฝ”๋”ฉ•ด ฃผ–ด•ผ •œ๋‹ค. ด๊ฒƒ€ žฌ‚ฌšฉ ด๋ž˜Šค๋กœ„œ ๋ณด๊ธฐ •Šข‹€๋ฐ, ด๊ฒƒ„ –ด๋–ป๊ฒŒ ž๋™™” • ˆ˜๋Š” —†„๊นŒ? C++๋Š” ด๋Ÿฐ žฌ‚ฌšฉ„ ง€›• ˆ˜ žˆ„๊นŒ.

œ ๋„ ๋ฐ›€ ด๋ž˜Šค—„œ ฐธกฐ นดšด„— ๊ด€๋ จ•œ ฝ”๋“œ๋ฅผ —†• ๊ธฐ, ๋งฒ˜๋Ÿผ ‰ฌšด ผ€ •„๋‹Œ๊ฒƒ ๊ฐ™๋‹ค. ๊ฐ๊ธฐ—๋‹ค๊ฐ€ String๊ฐ™€ ˜•˜ ๊ตฌ˜„„ œ„•ด„œ๋Š” non-const operator[]— ๋”ฐ๋ฅธ ๊ณตœ  —ฌ๋ถ€๊นŒง€ ๋”ฐ ธ ค˜•ผ •˜ง€ ๋”š ๋ณตžก•ด ง€๋Š” ๋ฌธ œด๋‹ค. ˜„žฌ String˜ ๊ฐ’„ ๋ณด๊ด€•˜๋Š”๊ฒƒ€ StringValueธ๋ฐ ด๋ ‡๊ฒŒ ‘œ˜„๋˜–ด žˆ๋‹ค.

~cpp 
class String {
private:
  struct StringValue: public RCObject { ... };
  StringValue *value;                // ด String˜ ๊ฐ’
  ...
};
StringValue ๊ฐฒด˜ refCount˜ ฆ๊ฐ„ œ„•ด„œ๋Š” ƒ๋‹นžˆ ๋งŽ€ –‘˜ ฝ”๋”ฉด ๋“ค–ด๊ฐ€•ผ • ๊ฒƒด๋‹ค. ๋ณต‚ฌ• ๋•Œ, žฌ • ๋‹น ๋ฐ›„๋•Œ, ๊ทธ๋ฆฌ๊ณ  •ด๋‹น ๊ฐ’ด ŒŒ๊ดด๋˜–ด ˆ๋•Œ, ด๋Ÿฐ ๋ชจ๋“ ๊ฒƒ„ ž๋™™” ‹œ‚ค๋Š” ๊ฒƒด ด๋ฒˆ žฅ˜ ๋ชฉ ด๋‹ค. —ฌ๊ธฐ„œ StringValue๋ฅผ  „žฅ— –ธ๊ธ‰–ˆ๋˜ Šค๋งˆŠธ ฌธ„ฐ ๊ธฐˆ „  šฉ•ด„œ ด๋Ÿฐ ฐธกฐ „ธ๊ธฐ— ๊ด€•ด„œ žฌ‚ฌšฉ„„˜–ด ž๋™™”๋ฅผ ‹œผœ ๋ณดž.

Šค๋งˆŠธ ฌธ„— ๋Œ€•œ „ค๋ช…€ ๋„ˆ๋ฌด ๋ฐฉ๋Œ€•˜๋‹ค. •˜ง€๋งŒ —ฌ๊ธฐ RCObject๋ฅผ ๊ฐ€๋ฆฌ‚ฌ Šค๋งˆŠธ ฌธ„ฐ๊ฐ€ ๊ฐ€ง€๊ณ  žˆ„ ๋Šฅ๋ ฅ€ ๋ฉค๋ฒ„ „ ƒ(->), —ญฐธกฐ(deferencing, *) —ฐ‚ฐž  •๋„๋งŒ žˆœผ๋ฉด ถฉ๋ถ„•˜๋‹ค. ๋ฌผ๋ก  ๋ณต‚ฌ๋‚˜, ƒ„€ ๊ธฐ๋ณธด๊ณ  ๋งด๋‹ค. ฐธกฐ „ธ๊ธฐ๋ฅผ œ„•œ Šค๋งˆŠธ ฌธ„…œ”Œ๋ฆฟ„ RCPtrด๋ผ๊ณ  ๋ช…๋ช…•˜๊ณ , ๊ธฐ๋ณธ ธ ๋ผˆ๋Œ€๋ฅผ ๋‹คŒ๊ณผ ๊ฐ™ด ๊ตฌ„•œ๋‹ค.

~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();                        // ๋ณด†ต˜ ˆ๊ธฐ™” ๋ฃจ‹ด
};
œ„—„œ –ธ๊ธ‰–ˆ๋“ฏด, …œ”Œ๋ฆฟ˜ ๋ชฉ € RCObject˜ refCount˜ ฆ๊ฐ„ ž๋™™”•˜๊ธฐ œ„•œ ๊ฒƒด๋‹ค. ˜ˆ๋ฅผ ๋“ค–ด„œ, RCPtrด ƒ„๋ ๋•Œ ๊ฐฒด๋Š” ฐธกฐ นดšด„ฐ๋ฅผ ฆ๊ฐ€‹œ‚ค‚ค ›•  ๊ฒƒด๊ณ , RCPtr˜ ƒ„ž๊ฐ€ ด๋ฅผ ˆ˜–‰•˜๊ธฐ ๋•Œ๋ฌธ— ด „ฒ˜๋Ÿผ ผผด ฝ”๋”ฉ•  •„š”๊ฐ€ —†„ ๊ฒƒด๋‹ค. ผ๋‹จ, ƒ„ ๋ถ€๋ถ„—„œ˜ ฆ๊ฐ€๋งŒ„ ƒ๊ฐ•ด ๋ณธ๋‹ค.

~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();             // ƒˆ๋กœšด ฐธกฐ นดšด„ฐ๋ฅผ ˜ฌ๋ฆฐ๋‹ค.
}
๊ณต†ต๋œ ฝ”๋“œ๋ฅผ init()œผ๋กœ ๋ฌถ—ˆ๋Š”๋ฐ, ด๋Ÿฐ ๊ฒฝšฐ  •™•žˆ ๋™ž‘•˜ง€ •Š„ˆ˜ žˆ๋‹ค. init•จˆ˜๊ฐ€ ƒˆ๋กœšด ๋ณต‚ฌ๋ณธ„ •„š”๋กœ • ๋•Œ๊ฐ€ ๊ทธ๊ฒƒธ๋ฐ, ๊ณตœ ๋ฅผ —ˆšฉ•˜ง€ •Š„ ๊ฒฝšฐ— ๋ณต‚ฌ•˜๋Š” ๋ฐ”๋กœ ด๋ถ€๋ถ„,

~cpp 
pointee = new T(*pointee);
opintee˜ ˜•€ pointer-to-Tด๋‹ค. •„๋งˆ Stringด๋ž˜Šค—„œ๋Š” ด๊ฒƒด String::StringValue˜ ๋ณต‚ฌ ƒ„ž ผ๊ฒƒธ๋ฐ, šฐ๋ฆฌ๋Š” StringValue˜ ๋ณต‚ฌ ƒ„ž๋ฅผ „ –ธ•ด ฃผง€ •Š•˜๋‹ค. ๊ทธ๋ž˜„œ ปดŒŒผ๋Ÿฌ๊ฐ€ ž๋™ œผ๋กœ C++๋‚ด˜ ๊ทœน™„ ง€‚ค๋ฉด„œ ๋ณต‚ฌ ƒ„ž๋ฅผ ๋งŒ๋“ค–ด ๋‚ผ๊ฒƒด๋‹ค. ๊ทธ๋ž˜„œ ๋ณต‚ฌ๋Š” ˜คง StringValue˜ data ฌธ„— •ด๋‹น•˜๋Š” ๊ฒƒ๋งŒด ด๋ฃจ–ด ˆ๊ฒƒด๋‹ค. data๋Š” ๋ณต‚ฌ๊ฐ€ •„๋‹Œ ฐธกฐ๊ฐ€ –‰•ด ˆ๊ฒƒด๋‹ค. ด๋Ÿฌ•œ ดœ ๋กœ ด›„, ž‘„๋˜๋Š” ๋ชจ๋“  ‹€๋ž˜Šค— ๋ณต‚ฌ ƒ„ž๊ฐ€ ถ”๊ฐ€๋˜–ด•ผ •œ๋‹ค.

RCPtr<T>˜  •™••œ ˆ˜–‰„ œ„•ด„œ T๋Š” ๋ณต‚ฌ ƒ„ž๋ฅผ ๊ฐ€ง€๊ณ  žˆ–ด„œ, ๋…๋ฆฝ œผ๋กœ ๋ณต‚ฌ๋ฅผ ˆ˜–‰•ด•ผ •œ๋‹ค.(๋‹ค๋ฅธ ๋ง๋กœ deep copy๊ฐ€ ด๋ฃจ–ด  ธ•ผ •œ๋‹ค.)

~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);                     // ˆ˜–‰ ๋ถ€๋ถ„ด๋‹ค.
}
ด๋Ÿฌ•œ deep-copy ๋ณต‚ฌ ƒ„ž˜ กดžฌ๋Š” RCPtr<T>๊ฐ€ ๊ฐ€๋ฆฌ‚ค๋Š” T— ๊ตญ•œ ๋˜๋Š” ๊ฒƒด •„๋‹ˆ๋ผ, RCObject๋ฅผ ƒ†•˜๋Š” ด๋ž˜Šค—๋„ ง€›๋˜–ด•ผ •œ๋‹ค. ‚ฌ‹ค RCPtr ๊ฐฒด ๊ด€ —„œ ๋ณผ๋•Œ๋Š” ˜คง ฐธกฐ „ธ๊ธฐ๋ฅผ •˜๋Š” ๊ฐฒด๋ฅผ ๊ฐ€๋ฆฌ‚ค๊ธฐ๋งŒ •˜๋Š” ๊ด€ —„œ ด๊ฒƒ€ ๋‚ฉ๋“• ˆ˜ —†๋Š” ‚ฌ‹คผง€ ๋ชจ๋ฅธ๋‹ค. ๊ทธ๋ ‡ง€๋งŒ ด๋Ÿฌ•œ ‚ฌ‹คด ๊ผญ ๋ฌธ„œ™” ๋˜–ด ด๋ผด–ธŠธ—๊ฒŒ •Œ๋ ค ธ•ผ •œ๋‹ค.

๋งˆง€๋ง‰ RCPtr<T>—„œ˜ ๊ฐ€„€ T— ๋Œ€•œ ˜•— ๊ด€•œ ๊ฒƒด๋‹ค. ด๊ฒƒ€ ™•‹ค•˜๊ฒŒ ๋ณดธ๋‹ค. ๊ฒฐ๊ตญ pointee๋Š” T* ˜•œผ๋กœ „ –ธ๋˜๋Š”๋ฐ, pointee๋Š” •„๋งˆ T๋กœ ๋ถ€„œ ๋„๋œ ด๋ž˜Šค ผง€ ๋ชจ๋ฅธ๋‹ค. ˜ˆ๋ฅผ ๋“คž๋ฉด ๋งŒ•ฝ ๋‹น‹ ด SepcialStringValue๋ผ๋Š” String::StringValue—„œ œ ๋„๋œ ด๋ž˜Šค๊ฐ€ กดžฌ •œ๋‹ค๋ฉด

~cpp 
class String {
private:
  struct StringValue: public RCObject { ... };
  struct SpecialStringValue: public StringValue { ... };
  ...
};
ผ๋‹จ šฐ๋ฆฌ๋Š” String— RCPtr<StingValue> ฌธ„ฐ๋กœ SpecialStringValue ๊ฐฒด๋ฅผ ๊ฐ€๋ฆฌ‚ค๋Š” ƒƒœ๋กœ ๋งŒ๋“ค–ด„œ ฌ•จ‹œ‚ฌˆ˜ žˆ๋‹ค. ด๋Ÿฌ•œ ๊ฒฝšฐ— šฐ๋ฆฌ๊ฐ€ ›•˜๋Š” init๊ฐ€ ๋˜ง€ •Š๋Š”๋‹ค.

~cpp 
pointee = new T(*pointee);      // T ๋Š” StringValueด๋‹ค, •˜ง€๋งŒ 
                                // pointee๊ฐ€ ๊ฐ€๋ฆฌ‚ค๋Š”๊ด SpecialStringValeด๋‹ค.
ฆ‰, SepcialStringValue˜ ๋ณต‚ฌ ƒ„ž๋ฅผ ๋ถ€๋ฅด๊ธธ ›•˜๋Š”๋ฐ, StringValue˜ ๋ณต‚ฌ ƒ„ž๊ฐ€ ๋ถˆ๋ฆฐ๋‹ค. šฐ๋ฆฌ๋Š” ด๋Ÿฌ•œ ๊ฒƒ„ ๊ฐ€ƒ ๋ณต‚ฌ ƒ„ž๋ฅผ จ„œ (Item 25 ฐธ๊ณ ) • ˆ˜ žˆ๋‹ค. •˜ง€๋งŒ, ด๊ฒƒ€ ๋””žธ๋•Œ ˜๋„•œ ๊ฒƒด •„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ—, ด๋Ÿฌ•œ ๊ฒฝšฐ— ๋Œ€•ด„œ๋Š” ๋‚ฉ๋“• ˆ˜๊ฐ€ —†๋‹ค.

ด œ, ƒ„ž— ๊ด€•œ ๋‚ดšฉ„ ๋ฒ—–ด๋‚˜, • ๋‹น(assignment) —ฐ‚ฐž— ๊ด€•œ ๋‚ดšฉ„ ๋‹ค๋ฃฌ๋‹ค. • ๋‹น ๊ฒฝšฐ๋„ ๊ณตœ ˜ ๊ฒฝšฐ๋ฅผ ƒ๊ฐ•ด•ผ •˜๊ธฐ ๋•Œ๋ฌธ— ๊นŒ๋‹ค๋กญ๊ฒŒ ๋ ˆ˜ žˆ๋Š”๋ฐ, ๋‹ค–‰Šค๋Ÿฝ๊ฒŒ ด๋ฏธ ๊ทธ๋Ÿฌ•œ ๊ณผ •€ init— ๊ณต†ต œผ๋กœ ๋“ค–ด žˆ๊ธฐ ๋•Œ๋ฌธ— ฝ”๋“œ๊ฐ€ ๊ฐ„๋‹จ•ด „๋‹ค.

~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(); // •Œ•„„œ ŒŒ๊ดด๋จ
}
ฃผ„—„œ™€ ๊ฐ™ด removeReference() ๋Š” ฐธกฐ นดšด„ฐ๊ฐ€ 0ด๋˜๋ฉด •ด๋‹น ๊ฐฒด๋ฅผ ŒŒ๊ดด•œ๋‹ค.

๋งˆง€๋ง‰œผ๋กœ, ด œ Šค๋งˆŠธ ฌธ„˜ ๋ฐ๋ฏธธ ฌธ„‰๋‚ด๋‚ด๋Š” ๋ถ€๋ถ„ด๋‹ค.

~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— ๊ตฌ˜„•œ ฐธกฐ„ธ๊ธฐ˜ ๊ฐœ๋…๋„๋ฅผ •Œ•„ ๋ณดž.


ด๋Ÿฌ•œ ๊ฐœ๋žต๋„๋Š” ๋‹คŒ๊ณผ ๊ฐ™€ ด๋ž˜Šค๋กœ  •˜ ๋˜–ด „๋‹ค.

~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::StringValue— ๋ณดด๋Š” init •จˆ˜—„œ ‹ ๊ฒฝ จ•ผ •œ๋‹ค.

ž ค‘š”•œ ด •„ด…œ„ ฒ˜Œ ‹œž‘• ๋•Œ Stringด๋ž˜Šค˜ ธ„Ž˜ดŠค™€ ๋‹ค๋ฅธ  €, ๋ณต‚ฌ ƒ„ž๋Š” –ด๋”” žˆ๋Š”๊ฐ€? • ๋‹น(assignment) —ฐ‚ฐž๋Š” –ด๋”” žˆ๋Š”๊ฐ€? ŒŒ๊ดดž๋Š” –ด๋”” žˆ๋Š”๊ฐ€?  •๋ง ‹ฌ๊ฐ•œ ž˜๋ชปœผ๋กœ ๋ณดดง€ •Š๋Š”๊ฐ€?•˜ง€๋งŒ ๊ • • ๊ฒƒ—†๋‹ค. ‚ฌ‹ค ด ๊ตฌ˜„ ˜•ƒœ๋Š” ™„ „•˜๋‹ค. ๋งŒ•ฝ ดœ ๋ฅผ ๋ชจ๋ฅด๊ฒ œผ๋ฉด, C++„ ข€๋” ๊ณต๋ถ€•ด๋ผ. (ž‘„žฃผ:ด๋Ÿฐ ๊ด๋ฐฉ„ ๋งˆฌ๋กœ ๋ฐ”๊พธ๋Š”..)

ด œ๋Š” ด๋Ÿฌ•œ •จˆ˜๋“คด ๋”ดƒ •„š” —†๋‹ค. ๋ฌผ๋ก  •„ง String๊ฐฒด˜ ๋ณต‚ฌ๋Š” ง€›๋œ๋‹ค. ๋ณต‚ฌ๋Š” ฐธกฐ„ธ๊ธฐ๋ฅผ ๊ธฐ๋ฐ˜•œ StringValue๊ฐฒด—„œ ด๋ฃจ–ด ง€๋Š” ๊ฒƒœผ๋กœ, Stringด๋ž˜Šค๋Š” ๋‹คด„ ด๋Ÿฐ ๊ฒƒ„ œ„•ด„œ •œ„๋„ ฝ”๋”ฉ•  •„š”๊ฐ€ —†๋‹ค. ๊ทธ ดœ ๋Š” ด œ ปดŒŒผ๋Ÿฌ๊ฐ€ ๋งŒ๋“ค ๋ณต‚ฌ ƒ„ž—๊ฒŒ ๋ชจ๋‘ ๋งก๊ฒจ ๋ฒ„๋ฆฌ๋ฉด ๊ธฐƒ€˜ ๊ฒƒ๋“ค€ ๋ชจ๋‘ ž๋™œผ๋กœ ƒ„๋œ๋‹ค. RCPtr€ Šค๋งˆŠธ ฌธ„ด๋‹ค. ๊ทธ‚ฌ‹ค„ ๊ธฐ–ต•˜๋ผ, ๋ณต‚ฌ‹œ ๋ชจ๋‘ Šค๋งˆŠธ ฌธ„ฐ๊ฐ€ ฐธกฐ๋ฅผ ๊ด€๋ฆฌ•ดค€๋‹ค.

ž, ด œ  „ฒด˜ ๊ตฌ˜„ฝ”๋“œ๋ฅผ ๋ณด—ฌ„ ฐจ๋ก€ด๋‹ค. ๋จผ € 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; }
๋‹คŒ€ RCPtr˜ ๊ตฌ˜„ ฝ”๋“œด๋‹ค.

~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; }
๋‹คŒ€ String::StringValue˜ ๊ตฌ˜„ ฝ”๋“œด๋‹ค.

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

ด œ ๋ชจ๋“ ๊ธ ๊ฐ‹ธ๋Š” String ด๋ž˜Šค˜ ๊ตฌ˜„ ฝ”๋“œด๋‹ค.

~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ด๋ž˜Šค๋ฅผ œ„•œ ฝ”๋“œ™€, ๊ทธ๋ƒฅ ๋”๋ฏธ(dumb)ฌธ„ฐ๋ฅผ ‚ฌšฉ•œ ด๋ž˜Šค(ฒ˜Œ— ฐธกฐ„ธ๊ธฐ ๊ตฌ˜„•œ๊ฒƒ)™€๋Š” ๋‘๊ฐ€ง€˜ ฐ ฐจด ด žˆ๋‹ค. ฒซ๋ฒˆงธ๋กœ ด ด๋ž˜Šค˜ ฝ”๋“œ๊ฐ€ ๊ต‰žฅžˆ  ๋‹ค๋Š”  ด๋‹ค. ดœ ๋Š”, RCPtrด ฐธกฐ„ธ๋Š” ž‘—…„ ๋ชจ๋‘ ๋งก•„„œ ด๋‹ค. ๋‘๋ฒˆงธ๋กœ๋Š” Šค๋งˆŠธ ฌธ„ฐ๋กœ ๊ตฒด–ˆง€๋งŒ, String˜ ฝ”๋“œ๊ฐ€ ๊˜ œ ง€๋œ๋‹ค๋Š”  ด๋‹ค. ‚ฌ‹ค ๋ณ€™”๋Š” operator[]—„œ๋งŒ ๊ณตœ ˜ ๊ฒฝšฐ๋ฅผ ฒดฌ•˜๋Š” ๋ฃจ‹ด ๋•Œ๋ฌธ— ๋ฐ”๋€Œ—ˆ๋‹ค. ด๋ ‡๊ฒŒ Šค๋งˆŠธ ฌธ„ฐ๋กœ„œ †ˆ˜ •ด•ผ•˜๋Š” ž‘—…๋“คด ๋งŽด „–ด ๋“ ๋‹ค.

๋Œ€๋‹จ•˜ง€ •Š€๊ฐ€? ๋ˆ„๊ฐ€ ๊ฐฒด๋ฅผ ‚ฌšฉ•˜ง€ •Š„๊นŒ? ๋ˆ„๊ฐ€ บกА™”๋ฅผ ๋ฐ˜๋Œ€• ๊นŒ? •˜ง€๋งŒ, ด๋Ÿฌ•œ ‹ ๊ธฐ•œ 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— ๊˜ ๋‹ค๋˜–ด žˆ๋‹ค. ๊ทธ๋ž˜„œ ด ด๋ž˜Šค˜ ๊ตฌ˜„ ƒ™ฉ„ ๋ณดž.

~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); }
RCPPtr„ RCPtr๊ณผ ˜คง ๋‘๊ฐ€ง€  —„œ ๋‹ค๋ฅธ๋‹ค. ฒซ๋ฒˆงธ๋Š” RCIPtrด ค‘๊ฐ„ กฐ •žธ CountHolder†ต•ด„œ  ‘๊ทผ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ RCPtr ๊ฐฒด๋Š” ๊ฐ’„ ง ‘ ๊ฐ€๋ฆฌ‚จ๋‹ค๋Š”  ด๋‹ค. ๋‘๋ฒˆงธ๋กœ๋Š” operator->™€ operator*„ ˜ค๋ฒ„๋กœ๋“œ(overload)•ด„œ copy-on-write— ž๋™ œผ๋กœ ๋Œ€‘• ˆ˜ žˆ๊ฒŒ •˜˜€๋‹ค.

๊ทธ๋Ÿผ RCIPtr— ๋น„•˜—ฌ RCWidget€ ƒ๋‹นžˆ ๊ตฌ˜„ด ๊ฐ„๋‹จ•˜๋‹ค. ๊˜ ๋ชจ๋“  ๊ธฐ๋Šฅด RCIPtr—„œ ๊ตฌ˜„๋˜—ˆ๊ณ , RCWidget€ ๊ทธ๊ฒƒ„ †ต•ด„œ ธž๋งŒ  „๋‹ฌ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธด๋‹ค.(delegate) ๋งŒ•ฝ Widgetด ๋‹คŒ๊ณผ ๊ฐ™ด ƒ๊ฒผ๋‹ค๋ฉด

~cpp 
class Widget {
public:
    Widget(int size);
    Widget(const Widget& rhs);
    ~Widget();
    Widget& operator=(const Widget& rhs);
    void doThis();
    int showThat() const;
};

RCWidget€ •„๋งˆ ด๋ ‡๊ฒŒ ๊ตฌ˜„๋  ๊ฒƒด๋‹ค.

~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.
  • ๊ฐฒด๋ฅผ ƒ„•˜๊ณ , ŒŒ๊ดด•˜๋Š”๋ฐ ๋†’€ ๋น„šฉ„ ง€๋ถˆ•ด•ผ •˜๊ฐ๋‚˜, ๋งŽ€ ๋ฉ”๋ชจ๋ฅผ ‚ฌšฉ•œ๋‹ค. ด๋Ÿฌ•œ ๊ฒฝšฐ กฐฐจ ฐธกฐ„ธ๊ธฐ๋Š” ๋งŽ€ ๊ฐฒด๊ฐ€ ๊ณตœ •˜๋ฉด • ˆ˜๋ก ๋น„šฉ„ „—ฌ „๊ฒƒด๋‹ค.
    • Object values are expensive to create or destroy, or they use lots of memory.


๊ฐ€žฅ ™•‹ค•œ ๋ฐฉ๋ฒ•€ ”„๋กœŒŒผ(profile)„ †ต•ด„œ ฐธกฐ„ธ๊ธฐ๊ฐ€ •„š”•œ ๋‚ฉ๋“•  ๋งŒ•œ ดœ ๋ฅผ ฐพ๋Š” ๊ฒƒด๋‹ค. ด๋Ÿฌ•œ ‹ ๋ขฐ๊ฐ€ ๊ฐ€๋Š” ๋ฐฉ๋ฒ•€ „๋Šฅ˜ ๋ณ‘๋ชฉ ˜„ƒด ผ–ด๋‚˜๋Š” ๋ถ€๋ถ„— ฐธกฐ„ธ๊ธฐ˜  šฉ„ †ต•ด„œ ๋” ๋†’€ šจœจ„ ๊ฐ€ง€๊ณ  ˜ฌˆ˜ žˆ๋‹ค๋Š” ฆ๊ฐ๊ฐ€ ๋ ๊ฒƒด๋‹ค. ˜คง ๊ฐœผ๋กœ ˜กด•˜—ฌ, ฐธกฐ„ธ๊ธฐ˜  šฉ€ —ญšจ๊ณผ๋ฅผ ๊ฐ€ ธ๋‹ค ˜ฌ๋ฟด๋‹ค.

ง€๊ธˆ๊นŒง€˜ ๊ตฌ˜„œผ๋กœ ฐธกฐ„ด๊ธ” ž๋ฃŒ๋Š” heap˜—ญ—๋งŒ „ –ธ• ˆ˜ žˆ๋‹ค. •„๋ฌด๋ฆฌ ง€—ญ ๋ณ€ˆ˜๋กœ „ –ธ•œ๋“ค, ๋‚ด๋ถ€—„œ ž๋ฃŒ๋Š” heap˜—ญ— „ –ธ•˜—ฌ, ๊ด€๋ฆฌ๋œ๋‹ค.  •™••œ „ –ธด๋œ ด๋ž˜Šค๋ฅผ ๋งŒ๋“ค–ด•ผ •˜๊ณ , ๊ทธ๋ž˜„œ ™•‹คžˆ ๋™ž‘•˜๋Š”๊ฐ€ ™•‹ • ˆ˜ žˆ๋Š” ๋ฒ„๊ทธ —†๋Š” ฝ”๋“œ๋ฅผ ๋งŒ๋“ค–ด•ผ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ด ฐธกฐ„ธ๊ธฐ ๊ธฐ๋ณธด๋ž˜Šค๊ฐ€ šฐ๋ฆฌ˜ †„ ˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋– ๋‚˜๋Š” ๊ฒƒ€ ‚ฌšฉ ๋ฐฉ๋ฒ•— ๋Œ€•˜—ฌ  •™••œ ๊ธฐˆ ด •„š”•˜๋‹ค.

DeleteMe)˜–ด๊ฐ€ งง€ง€ ๋’ค˜ ๋‚ดšฉ€ ง€๋ฃจ•œ ๊ฐ™€ † ๋ก ˜ —ฐ†๊ฐ™๋‹ค. ถ”๊ฐ€•  ๊ธฐšด๋„ •ˆ๋‚œ๋‹ค.

2. Item 30: Proxy

  • Item 30: ๋Œ€๋ฆฌž
๋ณด†ต šฐ๋ฆฌ๋Š” ผฐจ› ๋ฐฐ—ด„ ‚ฌšฉ•œ๋‹ค. •˜ง€๋งŒ ผ๋ฐ˜ œผ๋กœ ‹ค œ๋กœ ž๋ฃŒ˜ ‘œ˜„—๋Š” ๊ทธ๋Ÿฌง€๊ฐ€ ๋ชป•˜๋‹ค. ๋ถˆ–‰žˆ๋„ C++๋Š” ดฐจ› ดƒ˜ ž๋ฃŒ๊ตฌกฐ๋ฅผ ž˜ ทจ๊ธ‰•˜ง€ ๋ชป•œ๋‹ค. ตœ†Œ•œ ๋ฐฐ—ด— ๋Œ€•œ ง€›€ –ธ–ด๊ฐ€ ๊ฐ€ ธ•ผ•˜๋Š” ตœ†Œ•œ˜ ๋ฐฐ๋ คด๋‹ค.(ž‘„žฃผ:๋ฉ‹๋Œ€๋กœ ˜—ญ) FORTRANด๋‚˜ BASIC, COBOL—„œ ผฐจ›, ดฐจ›, ... ๋‹คฐจ› ๋ฐฐ—ด„ ๋งŒ๋“คˆ˜ žˆ๋‹ค. (๊ทธ๋ž˜, FORTRAN€ 7ฐจ› ๊นŒง€๋ฐ–— •ˆ๋œ๋‹ค. ด๊ฐ ๋”ดง€๋‹ค. ๋„˜–ด๊ฐ€ž) •˜ง€๋งŒ C++—„œ • ˆ˜ žˆ๋‚˜? ๋•Œ๋ก  ˜คง  •๋ ฌ„ œ„•ด„œ๋งŒ ผ๊ฒƒด๋‹ค.

ด ฝ”๋“œ๋Š” •ฉ๋ฒ•ด๋‹ค.:

~cpp 
int data[10][20];       // 2ฐจ› ๋ฐฐ—ด 10 by 20
•˜ง€๋งŒ ฐจ›˜ ฌ๊ธฐ๋Š” ๋ณ€ˆ˜๊ฐ€ ๋ ˆ˜ —†๋‹ค. ด๋Ÿฐ๊ฒƒด •ˆ๋œ๋‹ค.:

~cpp 
void processInput(int dim1, int dim2)
{
    int data[dim1][dim2];   // —๋Ÿฌ! ๋ฐฐ—ด˜ ฐจ›€ ๋‹จง€ ปดŒŒผ ค‘—๋งŒ ๊ฒฐ •๋œ๋‹ค.
    ...
}
ฐ๊ธฐ— Heap ˜—ญ— ๊ธฐ๋ฐ˜•œ • ๋‹น —ญ‹œ ๊ทœน™— –ด๊ธ‹๋‚œ๋‹ค.

~cpp 
int *data =  new int[dim1][dim2];   // —๋Ÿฌ!

2.1. Implementing Two-Dimensional Arrays ดฐจ› ๋ฐฐ—ด˜ ๊ตฌ˜„

๋‹คฐจ›˜ ๋ฐฐ—ด€ C++— ๋ฟ•„๋‹ˆ๋ผ. ๋‹ค๋ฅธ –ธ–ด—„œ๋„ œ šฉ•˜๋‹ค. ๊ทธ๋ž˜„œ ๋‹คฐจ› ๋ฐฐ—ด€ ตœ๊ทผ— ด๊ฒƒ๋“ค— ง€›•˜๋Š” ๋ฐฉ๋ฒ•— ๋Œ€•œ ค‘š”„ด ๋Œ€๋‘๋˜๊ณ  žˆ๋‹ค. ๋ณด†ต˜ ๋ฐฉ๋ฒ•€ C++—„œ ‘œค€ ค‘— •˜๋‚˜ด๋‹ค.(•„š”๋กœ•œ ๊ฐฒด๋ฅผ ‘œ˜„•˜๊ธฐ œ„•ด ด๋ž˜Šค๋ฅผ ๋งŒ๋“ ๋‹ค. •˜ง€๋งŒ •Œ๋งž๊ฒŒ ๊ตฌ˜„•˜๊ธฐ๊ฐ€ –ด๋ ต๋‹ค. ) ๋ฐ”๋กœ ดฐจ› ๋ฐฐ—ด— ๋Œ€•œ …œ”Œ๋ฆฟ„  •˜• ˆ˜ žˆ๋‹ค.

~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);  // ˜ณ๋‹ค
    ...
}
•˜ง€๋งŒ ด๋Ÿฌ•œ ๋ฐฐ—ด ๊ฐฒด˜ ‚ฌšฉ€ ™„๋ฒฝ•˜ง€ •Š๋‹ค. C™€ C++ƒ—„œ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•„  šฉ‹œ‚จ๋‹ค๋ฉด, ๊ด„˜ธ๋ฅผ ‚ฌšฉ•ด„œ ๊ฐฒด˜ index๋ฅผ ‚ฌšฉ• ˆ˜ žˆ–ด•ผ •œ๋‹ค.

~cpp 
cout << data[3][6];
๊ทธ๋ ‡ง€๋งŒ Array2Dƒ— ธ…Šค— ๊ด€•œธž๋ฅผ –ด๋–ป๊ฒŒ  •˜•˜๊ณ , ‚ฌšฉ• ๊นŒ?

ฒซ๋ฒˆงธ •˜๊ณ  ‹ถ€๊•„๋งˆ operator[][]๋ฅผ „ –ธ•ด ๋ฒ„๋ฆฌ๋Š” ๊ฒƒด๋‹ค. ด๋ ‡๊ฒŒ

~cpp 
template<class T>
class Array2D {
public:
    // ด๋Ÿฌ•œ „ –ธ€ ปดŒŒผ • ˆ˜ —†๋‹ค.
    T& operator[][](int index1, int index2);
    const T& operator[][](int index1, int index2) const;
    ...
};
๋ณดž๋งˆž ด —ฐ‚ฐž˜ ˜๋„๋ฅผ •Œ๊ฒƒด๋‹ค. •˜ง€๋งŒ operator[][]๋ž€๊„ –ธ• ˆ˜๊ฐ€ —†๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹น‹ ˜ ปดŒŒผ๋Ÿฌ—ญ‹œ ด๊ฒƒ„ ๊ฐ•ˆ•˜ง€ •Š„ ๊ฒƒด๋‹ค. (˜ค๋ฒ„๋กœ๋“œ(overload)™€ ๊ด€๋ จ•œ —ฐ‚ฐž๋“ค— ๊ด€•œ  •๋ณด๋Š” Item 7„ ฐธ๊ณ •˜๋ผ) šฐ๋ฆฌ๋Š” ๊ทธ™ธ˜ ๋‹ค๋ฅธ ๋ฐฉ•ˆ„ ฐพ•„•ผ •œ๋‹ค.

๋งŒ•ฝ ๋ฌธ๋ฒ• ๋•Œ๋ฌธ— ๊ณจ๋จธ๋ฆฌ๊ฐ€ •„”„๋‹ค๋ฉด, ๋ฐฐ—ด„ ง€›•˜๋Š” ๋งŽ€ –ธ–ด—„œ ‚ฌšฉ•˜๊ณ  žˆ๋Š” ๋ฐฉ๋ฒ•„ ๋”ฐ๋ผ„œ, ()๋ฅผ ดšฉ•˜๋Š” ธ…Šค˜  ‘๊ทผ„ ๋งŒ๋“ค–ด ๋ณผˆ˜๋„ žˆ๋‹ค. ()˜ ดšฉ€ ๋‹จง€ operator()๋ฅผ ˜ค๋ฒ„๋กœ๋“œ(overload)•˜๋ฉด ๋œ๋‹ค.

~cpp 
class Array2D {
public:
    // ด๋Ÿฐ ‚ฌ•ญ€ ž˜ ปดŒŒผ ๋œ๋‹ค.
    T& operator()(int index1, int index2);
    const T& operator()(int index1, int index2) const;
    ...
};
ด๋ผด–ธŠธ—„œ๋Š” ด๋ ‡๊ฒŒ ‚ฌšฉ•œ๋‹ค.

~cpp 
cout << data(3, 6);
ด๋Ÿฌ•œ ๊ตฌ˜„€ ‰ฝ๊ณ , ๋‹น‹ ด ‚ฌšฉ•˜๊ณ ž •˜๋Š” ๋งŽ€ ฐจ›—„œ ผ๋ฐ˜™” ‹œ‚ค๊ธฐ๋„ šฉด•˜๋‹ค. •˜ง€๋งŒ ๊ฒฐ ด žˆ๋Š”๋ฐ, Array2D ๊ฐฒด๋Š” built-in ๋ฐฐ—ด๊ฐ™ด ๋ณดดง€ •Š๋Š”๋‹ค๋Š”  ด๋‹ค. ‚ฌ‹ค œ„˜, ๊ฐ data˜ ธž๋“ค— ๋Œ€•˜—ฌ (3,4)๊ณผ ๊ฐ™€  ‘๊ทผ ๋ฐฉ๋ฒ•€ •จˆ˜ ˜ธถœ๊ณผ ๊ฐ™€ ๋ชจŠต„ •˜๊ณ  žˆ๋‹ค.

FORTRAN๊ณผ ๊ฐ™ด ๋ณดด๋Š” ด๋Ÿฌ•œ ๋ฐฐ—ด ‘œ˜„๋ฒ•ด ๋งˆŒ— ๋“คง€ •Š๋Š”๋‹ค๋ฉด, index —ฐ‚ฐž™€ ๊ฐ™€ ๊ฐœ๋…„ œผ๋กœ ๋‹ค‹œ ๋Œ•„๊ฐ€ ๋ณธ๋‹ค. operator[][]๋ฅผ ‚ฌšฉ•˜ง€ •Š๊ณ ๋„ •ฉ๋ฒ• œผ๋กœ ๋‹คŒ๊ณผ ๊ฐ™ด ๋ณดด๋Š” ฝ”๋“œ๋ฅผ ๊ตฌ˜„• ˆ˜๋Š” —†„๊นŒ?

~cpp int data[10][20];
...
cout << data[3][6];
–ด๋–ป๊ฒŒ •˜๋ฉด ๋ ๊นŒ? ๋ณ€ˆ˜ธ data๋Š” ‹ค œ๋กœ ดฐจ› ๋ฐฐ—ดด ๊ฒฐฝ” •„๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ€ 10๊ฐœ-ธž๊ฐ€ •˜๋‚˜˜ ฐจ›œผ๋กœ ๋œ ๋ฐฐ—ดœผ๋กœ ฃผ–ด„ ๊ฒƒด๋‹ค. 10๊ฐœ ธž๋Š” ๊ฐ๊ธฐ 20๊ฐœ˜ ธž๋ฅผ ๊ฐ€„ ๋ฐฐ—ด๋กœ ๋˜–ด žˆ๋‹ค. ๊ทธ๋ž˜„œ data36€ ‹ค œ๋กœ๋Š” (data3)6๋ฅผ ˜๋ฏธ•˜๋Š”๊ฒƒด๋‹ค. ๋‹ค‹œ ๋ง•˜ž๋ฉด, data˜ ๋„ค๋ฒˆงธ ธžธ ๋ฐฐ—ด˜ ผ๊ณ๋ฒˆงธ ธž. งง๊ฒŒ ๋ง•ด ๊ฐ’€ ฒ˜Œ ๊ด„˜ธ˜ ˜๋ฏธ๋Š” ๋˜๋‹ค๋ฅธ ๋ฐฐ—ดด๋‹ค. ๊ทธ๋ž˜„œ ๋‘๋ฒˆงธ ๊ด„˜ธ˜  šฉ€ ๋‘๋ฒˆงธ˜ ๋ฐฐ—ด๋กœ ๋ถ€„ธž๋ฅผ ๊ฐ€ง€๊ณ  ˜ค๋Š” ๊ฒƒด๋‹ค.

๊ฐ™€ ๋ฐฉ‹„ Array2D— operaotr[]๊ฐ€ ƒˆ๋กœšด ๊ฐฒดธ, Array1D๋ฅผ ๋ฐ˜™˜‹œ‚ค๋Š” ๋ฐฉ‹œผ๋กœ ’€–ด๋‚˜๊ฐ€ ๋ณดž. ›๋ž˜ ดฐจ› ๋ฐฐ—ด˜ •ˆ— กดžฌ•˜๋Š”, ๋ฐ˜™˜๋˜๋Š” ธž Array1D—„œ operator[]๋ฅผ ˜ค๋ฒ„๋กœ๋“œ• ˆ˜ žˆ๋‹ค.

~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];          // ˜ณ๋‹ค.
—ฌ๊ธฐ—„œ data3€ Array1D๋ฅผ ด•ผ๊ธฐ •˜๋Š” ๊ฒƒด๊ณ , operator[]๋Š” ๋‘๋ฒˆงธ ฐจ›— œ„น˜ (3,6)— žˆ๋Š” float๋ฅผ ˜ธถœ•œ๋‹ค.

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[]๋ฅผ ง€›•˜๋Š” ๋ฌธž—ด ˜•€ ด๋ผด–ธŠธ—๊ฒŒ ๋‹คŒ๊ณผ ๊ฐ™€ ฝ”๋“œ๋ฅผ —ˆšฉ•œ๋‹ค.

~cpp 
String s1, s2;		// ๋ฌธž—ด๊ณผ ๋น„Šท•œ ด๋ž˜Šค;”„๋ก‹œ˜ “ฐž„€ 
                    // ‘œค€ ๋ฌธž—ด ธ„Ž˜ดŠค๋ฅผ ๋”ฐ๋ฅด๋Š” ด๋ž˜Šค ˜•ƒœ๋ฅผ
					// œ ง€•œ๋‹ค.
...

cout << s1[5];      // s1 ฝ๊ธฐ

s2[5] = 'x';        // s2 “ฐ๊ธฐ

s1[3] = s2[8];      // s1 “ฐ๊ธฐ, s2 ฝ๊ธฐ
operator[] ๋Š” ๊ฐ๊ธฐ ๋‹ค๋ฅธ ๋ชฉ œผ๋กœ ˜ธถœ๋ ˆ˜ žˆŒ„ œ ˜•˜๋ผ: ๋ฌธž๋ฅผ ฝ๊ฐ๋‚˜ ˜น€ ๋ฌธž๋ฅผ “ฐ๊ฐ๋‚˜, ฝ๊ธฐ๋Š” rvalue˜ ˜•ƒœ๋กœ “ฐ—ฌง€๋„๋ก •Œ๋ ค ธ žˆ๋‹ค.; ๊ทธ๋Ÿผ “ฐ๊ธฐ๋Š” lvalue˜•ƒœ(r€ right hand value, l€ left ด•˜ ๊ฐ™Œ) ผ๋ฐ˜ œผ๋กœ lvalue˜ ˜๋ฏธ๋Š” ๊ฐฒด—„œ ๊ทธ๋Ÿฌ•œ ๊ฐฒด˜ ˆ˜ •„ ˜๋ฏธ•˜๋ฉฐ, rvalue๋Š” ˆ˜ •„ • ˆ˜ —†๋Š” ๊ฒƒ„ ˜๋ฏธ•œ๋‹ค.

ด๋Ÿฌ•œ ƒƒœ, ฆ‰ perator[]—„œ lvalue™€ rvalue๋ฅผ ๊ตฌ๋ถ„•ด•ผ๋งŒ •œ๋‹ค. ™œ๋ƒ•˜๋ฉด ฐธกฐ„ธ๊ธฐ๊ฐ€  šฉ๋œ ž๋ฃŒ๊ตฌกฐ˜ ๊ฒฝšฐ— ฝ๊ธฐ๋Š” “ฐ๊ธฐ— ๋น„•˜—ฌ ›”ฌ  € ๋น„šฉ„ †Œ๋ชจ•˜๊ธฐ ๋•Œ๋ฌธด๋‹ค. Item 29—„œ ฐธกฐ„ธ๊ธฐ ๊ฐฒด˜ “ฐ๊ธฐ๋Š” •„๋งˆ  „ฒด ž๋ฃŒ๊ตฌกฐ˜ ๋ณต‚ฌ๋ฅผ œ ๋„•˜ง€๋งŒ, ฝ๊ธฐ๋Š” ๊ฐ„๋‹จ•œ ๊ฐ’˜ ๋ฐ˜™˜„ ˜๋ฏธ•œ๋‹ค๊ณ  „ค๋ช…–ˆ๋‹ค. ๋ถˆ–‰žˆ๋„, operator[]˜ ๋‚ด๋ถ€—„œ, ด๋“ค˜ ˜ธถœ ๋ชฉ „ ๊ตฌ๋ถ„•  ๋ฐฉ๋ฒ•€ —†๋‹ค. operator[]๋Š” lvalue™€ rvalue˜ “ฐž„˜ ฐจด๋ฅผ ๊ตฌ๋ถ„• ˆ˜ —†๋‹ค.

"๊ทธ๋ ‡ง€๋งŒ ž ‹œ!" •˜๊ณ  ๋‹น‹ ด ๋ง•œ๋‹ค. "๊ผญ ๊ทธ๋Ÿด •„š”๊ฐ€ —†๋‹ค. operator[]˜ ƒˆ˜™” ๋œ ๊ฐœ๋…„ ๋ฐ›•„๋“ค—ฌ„œ operator[]˜ ฝ๊ธฐ™€ “ฐ๊ธฐ๋ฅผ ๊ตฌ๋ถ„•˜๋ฉด ๋˜ง€ •Š€๊ฐ€?" ด๋Ÿฌ•œ ๋‹ค๋ฅธ ธก๋ณ€œผ๋กœ ๋‹น‹ € šฐ๋ฆฌ—๊ฒŒ ๋ฌธ œ˜ •ด๊ฒฐ ๋ฐฉ‹„  œ•ˆ•œ๋‹ค.

~cpp 
class String {
public:
  const char& operator[](int index) const;       // ฝ๊ธฐ œ„•ด กดžฌ
  char& operator[](int index);                   // “ฐ๊ธฐ œ„•ด กดžฌ
  ...

};
๋ถˆ–‰žˆ๋„ ด๋Ÿฌ•œ ๊ฒƒ€ ˆ˜–‰๋˜ง€ •Š๋Š”๋‹ค. ปดŒŒผ๋Ÿฌ๋Š” const™€ non-const ๋ฉค๋ฒ„ •จˆ˜˜ ๊ตฌ๋ถ„„ ˜คง ๊ทธ ๊ฐฒด๊ฐ€ constธ๊ฐ€˜ —ฌ๋ถ€— ๋”ฐ๋ผ๋งŒ Œ๋‹จ•œ๋‹ค. ด๋Ÿฌ•œ ๊ตฌ˜„€, const๊ตฌ๋ณ„˜ ๋ชฉ „ œ„•ด •„๋ฌด๋Ÿฐ ˜–ฅ„ ๋ชป ๋ผนœ๋‹ค.

~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 ๊ฐฒดด๋‹ค.
๊ทธ๋Ÿฌ๋ฏ€๋กœ ด๋Ÿฐ ๋ฐฉ‹˜ operator[]˜ ˜ค๋ฒ„๋กœ๋“œ๋Š” ฝ๊ธฐ™€ “ฐ๊ธฐ˜ ๊ตฌ๋ถ„— ‹คŒจ•œ๋‹ค.


Item 29—„œ šฐ๋ฆฌ๋Š” operator[]๋ฅผ “ฐ๊ธฐ๋ฅผ œ„•ด„œ žฌ ๋””žธ–ˆ๋‹ค. •„๋งˆ ด๊‰ฝ๊ฒŒ ฌ๊ธฐ• ˆ˜๋Š” —†„ ๊บผ๋‹ค.(ž‘„žฃผ:–ผ๋งˆ๋‚˜ ๊ณ ƒ•˜๋ฉด„œ ๋ดค๋Š”๋ฐ, ๋ฐ”๊พธ๊ธฐ ‹ซง€.) Item 29˜ ๋””žธ€ lvalue™€ rvalue˜ ‚ฌšฉ„ ๊ตฌ๋ถ„•˜๋Š” ๊ฒƒด •„๋‹ˆ๋ผ, operator[]๋ฅผ ˜ธถœ•˜๋ฉด ๋ฌดกฐ๊“ฐ๊ธฐ๋กœ ทจ๊ธ‰•ด ๋ฒ„๋ฆฌ๋Š” ๊ฒƒด๋‹ค.

operator[]๊ฐ€ ฝ๊ธฐ™€ “ฐ๊ธฐ๋ฅผ ๊ตฌ๋ถ„ ๋ชป•˜ง€๋งŒ ผ๋‹จ šฐ๋ฆฌ๋Š” ๊ฐ€๋Šฅ•œ•œ ด๊ฒƒ„ ๊ตฌ˜„•ด ๋ณด๊ณ ž •˜๋Š” ž…žฅ—„œ  ‘๊ทผ•ด ๋ณดž. operator[]๊ฐ€ ๋ฐ˜™˜•œ ด›„— ฝ๊ธฐ™€ “ฐ๊ธฐ˜ ƒƒœ๋ฅผ •Œ•„๋‚ด๋Š” ๋ฐฉ๋ฒ•„ •„š”๋กœ •œ๋‹ค. ด๊ฒƒ˜ ˜๋ฏธ๋Š” •ž— ๋‹ค๋ฃจ—ˆ๋˜, lazy evaluation˜ ๊ฐœ๋…๊ณผ ๋น„Šท•˜ง€ •Š„๊นŒ?

”„๋ก‹œ ด๋ž˜Šค๋Š” šฐ๋ฆฌ๊ฐ€ •„š”•œ ‹œ๊ฐ„„ ๋ฒŒ–ด „ˆ˜ žˆ๋‹ค. šฐ๋ฆฌ๋Š” operator[]˜ ๋ฐ˜™˜ธž๋ฅผ ๋ฌธž๋Œ€‹ — ๋ฌธž—ด„ œ„•œ ”„๋ก‹œ ๊ฐฒด๋ฅผ ๋ฐ˜™˜•˜๋„๋ก ˆ˜ •• ˆ˜ žˆ๊ธฐ ๋•Œ๋ฌธด๋‹ค. šฐ๋ฆฌ๋Š” ด๋ ‡๊ฒŒ ”„๋ก‹œ๋ฅผ ‚ฌšฉ•ด„œ ‹œ๊ฐ„„ ๋ฒŒˆ˜ žˆ๋‹ค. ด ”„๋ก‹œ ด๋ž˜Šค๊ฐ€ ฝž๋•Œ, operator[]๊ฐ€ ฝ๊ธฐธง€ “ฐ๊ธฐธง€๋ฅผ •Œˆ˜ žˆ๋‹ค.

ผ๋‹จ †ŒŠค๋ฅผ ๋ณด๊ธฐ „— šฐ๋ฆฌ๊ฐ€ ”„๋ก‹œ๋ฅผ –ด๋–ป๊ฒŒ จ•ผ• ง€ „ธ๊ฐ€ง€˜ ˆœ„œ๋กœ ๋‚˜๋ˆ„–ด ƒ๊ฐ•˜ž.

  • ”„๋ก‹œ๋ฅผ ๋งŒ๋“ ๋‹ค. ๋‹ค‹œ ๋ง•ด ๋ฌธž—ด—„œ ๋ฌธž๋ฅผ ๋Œ€‹ •˜๋Š” ๊ฒƒ— •Œ๋งž๋„๋ก ๋งŒ๋“ ๋‹ค.
  • ”„๋ก‹œ๋ฅผ จ•ผ•  ๊ณณ, ฆ‰ ๋ฌธž—ด˜ ๊ธ€ž๋ฅผ • ๋‹น•  ๊ณณ—  šฉ•œ๋‹ค.  šฉ„ • ๋•Œ ”„๋ก‹œ๋Š” operaotr[]—„œ lvalue˜ “ฐž„œผ๋กœ ‚ฌšฉ๋œ๋‹ค.
  • ๋˜ ๋‹ค๋ฅธ ๋ฐฉ‹œผ๋กœ ”„๋ก‹œ๋ฅผ ‚ฌšฉ•œ๋‹ค. ด๋ ‡๊ฒŒ ‚ฌšฉ๋˜๋ฉด ”„๋ก‹œ๋Š” operator[]— ๋Œ€•œ rvalue˜ “ฐž„„ ๊ตฌ˜„•œ๋‹ค.

—ฌ๊ธฐ—„œ๋Š” ฐธกฐ„ธ๊ธฐ๊ฐ€  šฉ๋œ Stringด๋ž˜Šค— lvalue™€ rvalue˜ “ฐž„„ ๊ตฌ๋ณ„•˜๋Š” operator[]˜ ๋Šฅ๋ ฅ„ ๋ถ€—ฌ–ˆ๋‹ค.

~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;
};
Item 29—„œ˜ Stringด๋ž˜Šค˜ ตœข…๋ฒ„ „๊ณผ ด †ŒŠค๊ฐ€ ๋‹ค๋ฅธ € ˜คง ถ”๊ฐ€๋œ CharProxyด๋ž˜Šค— operator[] •จˆ˜๊ฐ€ ๊ตฌ˜„๋˜—ˆ๋‹ค๋Š”  ด๋‹ค. •˜ง€๋งŒ, ด๋ผด–ธŠธ ž…žฅ—„œ๋Š” ๋ณด†ต “ฐ๋Š”๊ฒƒฒ˜๋Ÿผ Stringด๋ž˜Šค๋ฅผ ‚ฌšฉ• ๋•Œ ด๋Ÿฌ•œ ‚ฌ‹ค„ ๋ฌด‹œ•˜๊ณ , operator[]•จˆ˜๊ฐ€ ๊ธ€ž๋ฅผ ๋ฐ˜™˜•˜๋Š” ๊ฒƒœผ๋กœ ทจ๊ธ‰•œ๋‹ค.


~cpp 
String s1, s2;  // ”„๋ก‹œ๋ฅผ ‚ฌšฉ•˜๋Š” ฐธกฐ „ธ๊ธฐ๊ฐ€  šฉ๋œ ๋ฌธž—ด
...
cout << s1[5];  // ˜ณ๋‹ค.

s2[5] = 'x';    // —ญ‹œ ˜ณ๋‹ค.

s1[3] = s2[8];  // —ญ‹œ๋‚˜ ž˜๋Œ•„๊ฐ„๋‹ค.
ด๋ ‡๊ฒŒ ›€งด๋Š” ๊ฒƒด ๊ด€‹ฌ‚ฌ๊ฐ€•„๋‹ˆ๋ผ, –ด๋–ป๊ฒŒ ›€งด๋А๋ƒ๊ฐ€ ๊ด€‹ฌ‚ฌ ผ๊ฒƒด๋‹ค.

๋งจฒ˜Œ— ด ๊ตฌ๋ฌธ„ ƒ๊ฐ•ด ๋ณดž.

~cpp 
cout << s1[5];

s15˜ ‘œ˜„€ CharProxy ๊ฐฒด๋ฅผ ๋ฐ˜™˜•œ๋‹ค. s15๊ฐ€ output(<<) ์—ฐ์‚ฐ์ž์— ๋Œ€ํ•˜์—ฌ ๊ฐ์ฒด์— ๋Œ€ํ•˜์—ฌ ์ •์˜๋œ๊ฒƒ์€ ์—†๋‹ค. ๊ทธ๋ž˜์„œ ๋‹น์‹ ์˜ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” operator<<์— ์ ์šฉํ• ์ˆ˜ ์žˆ๋Š” ์•”์‹œ์ (implicit) ํ˜•๋ณ€ํ™˜์„ ์ฐพ๋Š”๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๊ทธ๋ž˜์„œ ํ”„๋ก์‹œ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์„ ์–ธ๋˜์–ด ์žˆ๋Š” char()๋ฅผ ์ฐพ์„์ˆ˜ ์žˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ด(char) ํ˜•๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋ฅผ ์š”์ฒญํ•˜๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ CharProxy๋Š” ๋ฌธž๋กœ ๋ณ€™˜๋˜–ด„œ ถœ๋ จ๋˜–ด „๋‹ค. ๋‹ค‹œ ๋ง•˜ง€๋งŒ, ด๊ฒƒ€ CharProxy-to-char ๋กœ˜ ˜•๋ณ€™˜ด CharProxy๋‚ด๋ถ€— •”‹œ (implicit) ˜•๋ณ€™˜ด „ –ธ๋˜–ด žˆ๊ธฐ ๋•Œ๋ฌธด๋‹ค.

lvalue˜ ‚ฌšฉ€ ข€ ๋‹ค๋ฅด๊ฒŒ žกžˆ๋Š”๋ฐ, ด ๊ตฌ๋ฌธ„ ๋‹ค‹œ ๋ณดž.

~cpp 
s2[5] = 'x';
s25˜ ‘œ˜„€ CharProxy๊ฐฒด๋ฅผ ๋ฐ˜™˜•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  • ๋‹น(assignment)—ฐ‚ฐž˜ ๋ชฉ‘œ๊ฐ€ ๋œ๋‹ค.–ด๋–ค • ๋‹น(assignment) —ฐ‚ฐž๊ฐ€ ๋ถˆ๋ คง€๋Š” ๊ธ๊นŒ? • ๋‹น˜ ๋ชฉ‘œ๋Š” CharProxyด๋‹ค. ๊ทธ๋ž˜„œ • ๋‹น—ฐ‚ฐž๋Š” CharProxy ด๋ž˜Šค •ˆ—„œ ๋ถˆ๋ ค„๋‹ค. ด๊ฒƒ€ ค‘š”•œ ๊ฒƒด๋‹ค. ™œ๋ƒ•˜๋ฉด CharProxy˜ • ๋‹น(assignment) —ฐ‚ฐž๋ฅผ ‚ฌšฉ•˜๋Š”๊ฒƒœผ๋กœ šฐ๋ฆฌ๋Š” Stirng—„œ lvalue๋กœ„œ ด๋ฒˆ —ฐ‚ฐด ˆ˜–‰๋œ๋‹ค๋Š” ๊ฒƒ„ •Œˆ˜žˆ๋‹ค. ๊ทธ๋ž˜„œ šฐ๋ฆฌ๋Š” ๋ฌธž—ด ด๋ž˜Šค๊ฐ€ ด๋ฒˆ—๋Š” lvalue— •Œ๋งž๋Š” ๋™ž‘„ •ด•ผ •œ๋‹ค๋Š” ๊ฒฐ๋ก „ –ป๋Š”๋‹ค.

๋น„Šท•˜๊ฒŒ ๋‹คŒ๊ณผ ๊ฐ™€ ๊ตฌ๋ฌธ„ ๋ณด๋ฉด

~cpp 
s1[3] = s2[8];
ด๊ฒƒ€ ๋‘๊ฐœ˜ CharProxy๋ฅผ œ„•ด„œ • ๋‹น —ฐ‚ฐž๊ฐ€ ๋™ž‘•˜๊ณ , •˜๋‚˜๋Š” charœผ๋กœ •”‹œ  ๋ณ€™˜, ๋˜ •˜๋‚˜๋Š” CharProxy๊ฐฒด˜ • ๋‹น —ฐ‚ฐž๋ฅผ ‚ฌšฉ•˜๋Š” ๊ฒƒ
œผ๋กœ ๋‘˜€ 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);
}
๊ฐ •จˆ˜๋Š” ๋ฌธž š”๊ตฌ‹œ— CharProxy ๊ฐฒด๋ฅผ ๋งŒ๋“ค–ด„œ ๋ฐ˜™˜•œ๋‹ค. ๋ฌธž—ด€ ŠคŠค๋กœ๋Š” •„๋ฌด ผ„ •˜ง€ ๋ชป•œ๋‹ค. šฐ๋ฆฌ๋Š” ๊ทธ๋Ÿฌ•œ ๋™ž‘„ ฝ๊ธฐ™€ “ฐ๊ธฐ˜  ‘๊ทผ„ •Œˆ˜žˆ„๋•Œ ๊นŒง€ ง€—ฐ‹œ‚ค๋„๋ก ๋งŒ๋“ค–ด•ผ •œ๋‹ค.

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๋Š” ‘œ˜„„ œ„•˜—ฌ ๋ฌธž๋กœ„œ •„š”•œ ธ๋Šค™€ ๊ธ€ž  •๋ณด๋ฅผ ˆ˜๋ก•˜๊ณ  žˆ๋‹ค.

~cpp 
String::CharProxy::CharProxy(String& str, int index)
: theString(str), charIndex(index) {}
rvalue๋กœ˜ proxy˜ ˜•๋ณ€™˜€ ๊ณง๋ฐ”๋กœ ผ–ด ๋‚œ๋‹ค. ฆ‰, ๋‹จง€ proxy—„œ ˜•๋ณ€™˜œผ๋กœ •ด๋‹น•˜๋Š” ˆ˜–‰๋งŒ •ดฃผ๋ฉด ๋œ๋‹ค.

~cpp 
String::CharProxy::operator char() const
{
    return theString.value->data[charIndex];
}
๋งŒ•ฝ String๊ฐฒด™€ ๊ด€๊ณ„๋ฅผ ฝ–ด ๋ฒ„๋ ธ๋‹ค๋ฉด, value ๋ฉค๋ฒ„™€ data ๋ฉค๋ฒ„™€˜ ๊ด€๊ณ„— ๋Œ€•˜—ฌ Itmem 29๋ฅผ ๋ณด๊ณ  ๊ธฐ–ต•ด๋ผ. ด •จˆ˜๋Š” ๋ฌธž๋ฅผ ๊ฐ’œผ๋กœ(by-value)๋กœ  „๋‹ฌ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  C++€ ๊ทธ๋Ÿฌ•œ ๊ฐ’œผ๋กœ(by-value)  „๋‹ฌ„ ๋ฐ˜™˜ ๊ฐ’œผ๋กœ๋งŒ ๋ฐ˜™˜ ๊ฐ’„ ‚ฌšฉ•˜๋„๋ก  œ•œ•˜๊ธฐ ๋•Œ๋ฌธ— ๋‹คŒ๊ณผ ๊ฐ™€ ˜•๋ณ€™˜ •จˆ˜๋Š” ˜คง rvalue๋•Œ๋งŒ œ šจ•˜๋‹ค.

๊ทธ๋ž˜„œ CharProxy˜ • ๋‹น(assignment) —ฐ‚ฐž ๊ตฌ˜„œผ๋กœ lvalue— •ด๋‹น•˜๋Š” ž‘—…๋งŒ ๊ฐ€๋Šฅ•˜๊ฒŒ ๊ตฌ˜„• ˆ˜ žˆ๋‹ค. ด œ CharProxy˜ • ๋‹น —ฐ‚ฐž๋ฅผ ๋‹คŒ๊ณผ ๊ฐ™ด ๊ตฌ˜„•œ๋‹ค.

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

Item 29— ๋‚˜™€žˆ๋Š”, non-const String::operator[]๊ณผ ๋น„๊ต•ด๋ณด๋ฉด ธƒ ธ ๋А๋‚Œด ˜ฌ๊ฒƒด๋‹ค. ด๊ฒƒ€ ˜ˆธก• ˆ˜ žˆ๋‹ค. Item29—„œ๋Š” ด๋Ÿฌ•œ “ฐ๊ธฐ™€ ฝ๊ธฐ๋ฅผ ๊ตฌ๋ถ„•˜ง€ ๋ชป•ด„œ ๋ฌดกฐ๊ด non-const operator[]๋ฅผ “ฐ๊ธฐ๋กœ ทจ๊ธ‰–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ , CharProxy๋Š” String— ๋Œ€•œ žœ ๋กœšด  ‘๊ทผ„ œ„•ด friend๋กœ „ –ธ–ˆ๊ธฐ— ๋ฌธž๊ฐ’˜ ๋ณต‚ฌ ๊ณผ •˜ ˆ˜–‰ด ๊ฐ€๋Šฅ•˜๋‹ค.

ด œ ๋‚˜๋จธง€ ง ‘ ๋ฌธž—ดด ž…๋ ฅ๋ ๋•Œ๋ฅผ ๊ตฌ˜„•œ๋‹ค.

~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;
}
Software Engineer„ ˆ˜–‰•˜๋Š” ž…žฅด๋ผ๋ฉด ๋ฌผ๋ก  ด™€ ๊ฐ™ด CharProxy๋ฅผ †ต•ด„œ ฝ๊ธฐ™€ “ฐ๊ธฐ๋ฅผ ๊ตฌ๋ถ„•ด„œ, ๋ณต‚ฌ— •ด๋‹น•˜๋Š” ฝ”๋“œ๋ฅผ ‚ญ œ•ด•ผ •œ๋‹ค.•˜ง€๋งŒ ด๊ฒƒ— ๋Œ€•œ ๊ฒฐ „ ƒ๊ฐ•ด ๋ณดž.

2.3. Limitations :  œ•œ

proxy ด๋ž˜Šค˜ ‚ฌšฉ€ operator[] ‚ฌšฉ‹œ lvalue™€ rvalue˜ ๊ตฌ๋ถ„„ ๋ช…๋ฃŒ•˜๊ฒŒ •œ๋‹ค. ๊ทธ๋ ‡ง€๋งŒ ๋ฌด‹œ• ˆ˜ —†๋Š” ๊ฒฐ „ ๊ฐ€ง€๊ณ  žˆ๋‹ค. proxy๊ฐฒด๋Š” ๊ทธ๋“คด ๋ชฉ‘œ•˜๋Š” ๊ฐฒด๋ฅผ ™„ „žˆ ๊ตฒด•˜๋Š” ๊ฒƒด ๋ชฉ‘œง€๋งŒ  •๋ง –ด๋ ต๋‹ค. —ฌ๊ธฐ—„œ ๋ฌธžฒ˜๋Ÿผ, lvalue™€ rvalue˜ ๋ชฉ ๋ฟ •„๋‹ˆ๋ผ. ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•œผ๋กœ ๊ฐฒด๋Š”  ‘๊ทผ๋ ˆ˜ žˆ๋‹ค.

Item 29— –ธ๊ธ‰๋œ ๊ณตœ ”Œ๋ž˜๊ทธ๋ฅผ ๋”•œ StringValue๊ฐฒด— ๊ด€•ด„œ ๋‹ค‹œ ƒ๊ฐ•ด ๋ณดž. ๋งŒ•ฝ String::operator[] ๊ฐ€ char&๋Œ€‹ — CharProxy๋ฅผ ๋ฐ˜™˜•œ๋‹ค๋ฉด ด๋Ÿฌ•œ ๊ฒฝšฐ๋Š” ๋”ดƒ ปดŒŒผ • ˆ˜๊ฐ€ —†๋‹ค.

~cpp 
String s1 = "Hello";
char *p = &s1[1];            // —๋Ÿฌ!
s11˜ ‘œ˜„€ CharProxy๋ฅผ ๋ฐ˜™˜•˜๊ธฐ ๋•Œ๋ฌธ—, ๋‘๋ฒˆงธ—„œ ˜ค๋ฅธชฝ˜ ˜๋ฏธ๋Š” CharProxy*๋ฅผ ๋ฐ˜™˜•˜๋Š” ๊ฒƒด๋‹ค. •˜ง€๋งŒ CharProxy*๋ฅผ char*๋กœ ๋ฐ”๊พธ๋Š” ˜•๋ณ€™˜€ —ˆšฉ๋˜ง€ •Š๊ธฐ๋•Œ๋ฌธ— p˜ ˆ๊ธฐ™”—„œ ปดŒŒผ๋Ÿฌ๋Š” —๋Ÿฌ๋ฅผ ๋‚ธ๋‹ค. ผ๋ฐ˜ œผ๋กœ proxy˜ ฃผ†Œ๋Š” ‹ค œ ๊ฐฒด๋ณด๋‹ค ๋‹ค๋ฅธ ฌธ„ƒ€ž…„ ๊ฐ€„๋‹ค.

ด๋Ÿฌ•œ ๋ฌธ œ๋ฅผ  œ๊•˜๊ธฐ œ„•˜—ฌ ฃผ†Œ— ๊ด€•œ —ฐ‚ฐž๋ฅผ CharProxy ด๋ž˜Šค— ˜ค๋ฒ„๋กœ๋“œ(overload)•œ๋‹ค.

~cpp 
class String {
public:
    class CharProxy {
    public:
        ...
        char * operator&();
        const char * operator&() const;
        ...
    };
    ...
};
ด •จˆ˜๋Š” ๊ตฌ˜„•˜๊ธฐ ‰ฝ๋‹ค. const •จˆ˜๋Š” ๋‹จง€ const ๋ฒ„ „˜ ๋ฌธž˜ ฌธ„ฐ๋ฅผ ”„๋ก‹œ ด๋ž˜Šค๋กœ  „๋‹ฌ•˜๋ฉด ๋œ๋‹ค.

~cpp 
const char * String::CharProxy::operator&() const
{
    return &(theString.value->data[charIndex]);
}

non-const •จˆ˜˜ ๊ฒฝšฐ ข€๋” ‹ ๊ฒฝ“ธ๊ฒƒด ๋งŽ€๋ฐ, ๋ฐ˜™˜๋˜๋Š” ฌธ„˜ ๋ฌธž๊ฐ€ ˆ˜ • ๊ฐ€๋Šฅ„ด žˆ๊ธฐ ๋•Œ๋ฌธด๋‹ค. ด๋Ÿฌ•œ ๊ฒฝšฐ๋Š” Item 29—„œ ๋‹ค๋ฃจ—ˆ๋˜ non-const ๋ฒ„ „˜ String::operator[]˜ ๋ชจŠต๊ณผ ๋น„Šท•˜๋‹ค.๊ทธ๋ฆฌ๊ณ  ๊ตฌ˜„ —ญ‹œ ๋น„Šท•˜๋‹ค.

~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˜ ๋‹ค๋ฅธ ๋ฉค๋ฒ„ •จˆ˜๋“ค๊ณผ ๊ฐ™ด ‰๋ฒ”•˜๋‹ค.

๋‘๋ฒˆงธ˜ ๊ฒฐ๊ณผ, CharProxy๊ฐ€ ๋‹ค๋ฅธ € lvalue™€ rvalue˜ ๊ตฌ๋ถ„„ œ„•ด 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];                       // —๋Ÿฌ!
˜ˆƒ๋˜๋Š” ๋Œ€๋กœ operator[]˜ ๋ชฉ‘œธ ๊ฐ„๋‹จ•œ • ๋‹น(assignment)€ „๊ณต•˜ง€๋งŒ, left-hand˜ operator[]—„œ operator+=ด๋‹ˆ operator-=๋ฅผ ˜ธถœ•˜๋Š”๊‹คŒจ•œ๋‹ค. ™œ๋ƒ•˜๋ฉด operator[]๊ฐ€ ๋ฐ˜™˜•˜๋Š” ๊ฒƒ€ ”„๋ก‹œ ๊ฐฒด ด๊ธฐ ๋–„๋ฌธด๋‹ค. ๋น„Šท•œ ๊ฒฝšฐ— กดžฌ•˜๋Š” ๋ชจ๋“  —ฐ‚ฐž๊ฐ€ ‹คŒจ•œ๋‹ค. operator*=, operator/=, operator<<=, operator-= ๋“ฑ ๋ง์ด๋‹ค. ๋งŒ์•ฝ ์ด๋Ÿฐ ์ˆ˜ํ–‰์„ ์›ํ•œ๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋ฅผ ๋ชจ๋‘ ์„ ์–ธํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Š” ๋„ˆ๋ฌด ์ผ์ด ๋งŽ๋‹ค ๊ทธ๋ฆฌ๊ณ  ์•„๋งˆ ์›ํ•˜์ง€๋„ ์•Š์„ ๊ฒƒ์ด๋‹ค. ์ถ”๊ฐ€ํ•œ๋“ค ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์€๋“ค ๋‘˜๋‹ค ๊ดด๋กœ์šด ์ผ์ด๋‹ค.

๊ด€๊ณ„žˆ๋Š” ๋ฌธ œ๋กœ ”„๋ก‹œ๋ฅผ †ต•œ ‹ค œ ๊ฒฒด˜ ˜ธถœ—„œ ผ–ด๋‚ ˆ˜ žˆ๋Š”๋ฐ, • ˆ˜ —†๋Š”๊ฒƒ— ๊ด€•œ ๋ชจ˜ธ„ด๋‹ค. ˜ˆ๋ฅผ๋“ค–ด„œ, œ ๋ฆฌˆ˜ ๋ฐฐ—ด„ ฐธกฐ„ธ๊ธฐ๋กœ ๊ตฌ˜„–ˆ๋‹ค๊ณ  •ด๋ณดž. ด๊ฒƒ„ Rational ด๋ž˜Šค๋กœ  •˜•˜๊ณ  Array …œ”Œ๋ฆฟ„ ‚ฌšฉ•œ๋‹ค. ฝ”๋“œ๋Š” ๋‹คŒ๊ณผ ๊ฐ™๋‹ค.

~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();              // —๋Ÿฌ!
ด๋Ÿฌ•œ –ด๋ ค›€€ ถฉ๋ถ„žˆ ˜ˆƒ๋œ๋‹ค. operator[]๊ฐ€ ๋ฐ˜™˜•˜๋Š” œ ๋ฆฌˆ˜— ๊ด€•œ ”„๋ก‹œดง€ „งœ Rational๊ฐฒด๊ฐ€ •„๋‹ˆ๋‹ค. numerator๊ณผ denominator ๋ฉค๋ฒ„ •จˆ˜๋Š” Rationalœ„•ด„œ๋งŒ กดžฌ•˜ง€ ”„๋ก‹œ๋ฅผ œ„•ด„œ๋Š” กดžฌ•˜ง€ •Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ปดŒŒผ๋Ÿฌ๊ฐ€ ด— ๋Œ€•œ ˆ˜–‰„ ๋ชป•œ๋‹ค. ”„๋ก‹œ๋ฅผ ๋งŒ๋“œ๋Š”๊ฒƒ€ ๊ทธ๋“คด ˜๋ฏธ•˜๋Š” ๊ฐฒด™€ ๋น„Šท•œ๊ง€ ™„ „žˆ ๋™ผ•œ ๊ฐฒด˜ ๊ธฐ๋Šฅ„  œ๊ณต• ˆ˜ —†๋‹ค.

•„ง๋„ ”„๋ก‹œ๊ฐ€ „งœ ๊ฐฒด๋ฅผ ๊ตฒด•˜๊ธฐ ž˜๋“  ๋ฌธ œ๋Š” ๋‚จ•„ žˆ๋‹ค. ๋‹คŒ๊ณผ ๊ฐ™ด reference๋กœ ๋„˜๊ธธ๋•Œ กฐฐจ ๋งด๋‹ค.

~cpp 
void swap(char& a, char& b);    // a ™€ b˜ ๊ฐ’„ ๋ฐ”๊พผ๋‹ค.

String s = "+C+";               // —๊ตฌ, ด๊ด ๋ฌธž—ด€ "C++" ผ…๋ฐ.

swap(s[0], s[1]);               // ๊ทธ๊ฒƒ„ ๊ณ น ๋ ค๊ณ  •œ๋‹ค.
String::operator[]๋Š” CharProxy๋ฅผ ๋ฐ˜™˜•˜ง€๋งŒ swap๊ฐ€ ›•˜๋Š” ๊ฒƒ€ char&ด๋‹ค. CharProxy๋Š” •„๋งˆ •”‹œ (implicit) ˜•๋ณ€™˜œผ๋กœ char๋กœ ๋ณ€™”• ๊ฒƒด๊ณ  char&๋กœ๋Š” ๋ณ€™˜ด •„š” —†๋‹ค. ๊ฐœ๋‹ค๊ฐ€ ˜•๋ณ€™˜๋œ char€ swap๋‚ด๋ถ€—„œ ˆ˜–‰— †Œšฉด —†๋‹ค. ™œ๋ƒ•˜๋ฉด, char€ ž„‹œ ๊ฐฒดด๊ธฐ ๋•Œ๋ฌธด๋‹ค. ด— ๋Œ€•œ๊ฒƒ€ Item 19— ž„žˆ –ธ๊ธ‰๋˜–ด žˆ๋‹ค.

๋งˆง€๋ง‰ ”„๋ก‹œ๊ฐ€ ‹คŒจ•˜๋Š” „งœ ๊ฐฒด๋ฅผ ๊ตฒด•˜ง€ ๋ชป•˜๋Š” ƒ™ฉ€ •”‹œ (implicit) ˜•๋ณ€™˜—„œ ๊ธฐธ•œ๋‹ค. ”„๋ก‹œ ๊ฐฒด๋Š” •”‹œ (implicit)œผ๋กœ „งœ ๊ฐฒด๋กœ ˜•๋ณ€™˜• ๋•Œ user-defined ˜•๋ณ€™˜ •จˆ˜๊ฐ€ ๋ถˆ๋ฆฐ๋‹ค. ˜ˆ๋ฅผ๋“ค–ด„œ CharProxy๋Š” char๋กœ operator char„ ˜ธถœ•ด„œ ๋ณ€™”•œ๋‹ค. Item 5˜ „ค๋ช…„ ๋ณด๋ฉด ปดŒŒผ๋Ÿฌ๋Š” user-defined ˜•๋ณ€™˜ •จˆ˜๋ฅผ ๋ฐ˜‘•˜๋Š” ธž๋กœ˜ •„š”„ด žˆ๋Š” ๋ถ€๋ถ„—„œ •ด๋‹น —ฐ‚ฐ„ ˜ธถœ•œ๋‹ค๊ณ  •œ๋‹ค. ๊ฒฐ๊ตญ •จˆ˜ ˜ธถœ€ ”„๋ก‹œ๊ฐ€  „๋‹ฌ๋ ๋•Œ ‹คŒจ•˜๋ฉด ‹ค œ ๊ฐฒด๋ฅผ ๋„˜๊ธฐ๋Š” ๊ฒƒ„ „๊ณต‹œผœ„œ ๊ฐ€๋Šฅ•œ ๊ฒƒด๋‹ค. ˜ˆ๋ฅผ๋“ค–ด„œ TVStation๋ฆฌ•˜๋Š” ด๋ž˜Šค— watchTV •จˆ˜๊ฐ€ žˆ๋‹ค๊ณ  •œ๋‹ค๋ฉด:

~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);
ด ๋ฌธ œ๋Š” •”‹œ  ˜•๋ณ€™˜ด ฃผ๋Š” ๋˜ •˜๋‚˜˜ ๋ฌธ œด๋‹ค. ด๊ฒƒ„ •ด๊ฒฐ•˜๊ธฐ๋Š” –ด๋ ต๋‹ค. ‚ฌ‹ค TVStation— ƒ„ž๋ฅผ explicit๋กœ „ –ธ•˜๋Š” ๊ฒƒด ๋” ข‹€ ๋””žธผ ๊ฒƒด๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด watchTV—„œ ปดŒŒผด ‹คŒจ•œ๋‹ค. explicit— ๊ด€•œ ž„•œ „ค๋ช…€ Item 5๋ฅผ ฐธ๊ณ •˜๋ผ

2.4. Evaluation : ‰๊ฐ€

Proxyด๋ž˜Šค๋Š” ๊ตฌ˜„•˜๊ธฐ –ด๋ คšด –ด๋–ค ƒ™ฉ—„œ •ด๊ฒฐ…ด ๋ ˆ˜ žˆ๋‹ค. ๋‹คฐจ› ๋ฐฐ—ดด ฒซ๋ฒˆงธ, lvaue/rvalue๊ฐ€ ๋‘๋ฒˆงธ , •”‹œ  ˜•๋ณ€™˜ ๊ธˆง€๊ฐ€ „ธ๋ฒˆงธ ด๋‹ค.

๋˜ Proxy ด๋ž˜Šค๋Š” ๋‹จ ๋„ ๋งŽด๋„ ๊ฐ€ง€๊ณ  žˆ๋‹ค. •จˆ˜๊ฐ€ ๊ฐ’„ ๋ฐ˜™˜• ๋•Œ ”„๋ก‹œ ๊ฐฒด๋“ค€ ž„‹œ ธž(temporaries:Item 19ฐธ๊ณ )๋กœ  „๋‹ฌ๋œ๋‹ค. ๊ทธ๋ž˜„œ ๊ทธ๋“ค€ ƒ„, ‚ญ œ๋œ๋‹ค. ด๊ฒƒ€ ๊ณตงœ๊ฐ€ •„๋‹ˆ๋‹ค. ฝ๊ธฐ™€ “ฐ๊ธฐ˜ ๊ฒฝšฐ๋ฅผ ๊ฐ€๋ฆฌ๊ธฐ œ„•œ กฐน˜๋„, ž„‹œธž๋ฅผ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ— ๋น„šฉด ๋ฐœƒ•œ๋‹ค. ”„๋ก‹œ ด๋ž˜Šค๊ฐ€ žˆ–ด„œ †Œ”„Šธ›–ด ๊ตฌกฐ๋Š” ๋ณตžก•ด „๋‹ค. ๋” –ด๋ คšด ๋””žธ, ๊ตฌ˜„, ด•ด ๊ทธ๋ฆฌ๊ณ  œ ง€ ๋ณดˆ˜..

๋งˆง€๋ง‰œผ๋กœ „งœ ๊ฐฒด— ๋Œ€•œ ผ˜ ๋Œ€–‰€ ข…ข… ๋ฌธ๋ฒ•˜  œ•œ„ ๊ฐ€ง€๊ณ  ˜จ๋‹ค. ™œ๋ƒ•˜๋ฉด ”„๋ก‹œ ๊ฐฒด๊ฐ€ ‹ค œ ๊ฐฒด๋ฅผ ™„ „žˆ ๊ตฒด• ๋งŒผ ๋Šฅ๋ ฅ„ ๊ฐ€ˆˆ˜ —†๊ธฐ ๋•Œ๋ฌธด๋‹ค. ๋Œ€๋กœ ”„๋ก‹œ๋Š” ‹œŠค…œ˜ ๋””žธ‹œ ๋” ๋‚˜œ „ ƒ„ ๊ฐ€ง€๊ณ  ˜จ๋‹ค. •˜ง€๋งŒ ๋งŽ€ ๊ฒฝšฐ ”„๋ก‹œ˜ กด œ๋Š” ด๋ผด–ธŠธ—๊ฒŒ ๊ทธ ˆ˜–‰„ ˜‹•˜๊ฒŒ •˜๋Š” ๊ฒฝšฐ๋Š” ๊˜ —†๋‹ค. ˜ˆ๋ฅผ ๋“ค–ด„œ ด๋ผด–ธŠธ๋Š” ดฐจ› ๋ฐฐ—ด˜ ˜ˆ œ—„œ Array1D ๊ฐฒด˜ ฃผ†Œ๋ฅผ ›•˜๋Š” ด๋ผด–ธŠธ๋Š” ๊˜ —†๋‹ค. ๊ทธ๋ฆฌ๊ณ  ArrayIndex๊ฐฒด(Item 5ฐธ๊ณ )๋Š” ˜ˆƒ๋˜๋Š” ๋‹ค๋ฅธ ˜•ƒœ˜ •จˆ˜๋กœ  „๋‹ฌ ๋ ๊ฒƒด๋‹ค. ๋งŽ€ ๊ฒฝšฐ— ”„๋ก‹œ๋Š” „งœ ๊ฐฒด˜ ˆ˜–‰„ ๋Œ€–‰•œ๋‹ค. ๊ทธ๋“ค„  šฉ• ๋•Œ, •„๋ฌดผ —†๋Š”๊ด ๊˜ ๋Œ€๋ถ€๋ถ„ด๋‹ค.


Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:23:49
Processing time 0.1533 sec