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์ฐธ๊ณ )๋ ์์๋๋ ๋ค๋ฅธ ํํ์ ํจ์๋ก ์ ๋ฌ ๋ ๊ฒ์ด๋ค. ๋ง์ ๊ฒฝ์ฐ์ ํ๋ก์๋ ์ง์ง ๊ฐ์ฒด์ ์ํ์ ๋ํํ๋ค. ๊ทธ๋ค์ ์ ์ฉํ ๋, ์๋ฌด์ผ ์๋๊ฑด ๊ฑฐ์ ๋๋ถ๋ถ์ด๋ค.