AcceleratedC++/Chapter13 | AcceleratedC++/Chapter15 |
1. Chapter 14 Managing memory (almost) automatically ¶
Student_info ํด๋์ค๋ ๋ ์ฝ๋์ ์ธํฐํ์ด์ค. ๋ ์ฝ๋์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ด๋ฆฌํ๋ค.
์ด๋ ๊ฒ 2๊ฐ์ง์ ์ถ์์ ์ธ ๊ธฐ๋ฅ์ ์กฐํฉํด์ ๋ง๋ค๊ฒ ๋๋ ๊ฒ์ ํ์ ํ ํด๋์ค ์ค๊ณ๋๋ฌธ์ธ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
์ด๋ ๊ฒ 2๊ฐ์ง์ ์ถ์์ ์ธ ๊ธฐ๋ฅ์ ์กฐํฉํด์ ๋ง๋ค๊ฒ ๋๋ ๊ฒ์ ํ์ ํ ํด๋์ค ์ค๊ณ๋๋ฌธ์ธ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
์ด ์ฅ์์๋ ํฌ์ธํฐ์ฒ๋ผ ๋์ํ์ง๋ง, ์์ฒด ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ํฌํจํ๋ ํด๋์ค๋ฅผ ์์ฑํ๋ ค๊ณ ํฉ๋๋ค.
๋ด๋ถ์ ํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ์ ๋น์ทํ ๊ฐ์ฒด๋ฅผ ์ ์ ํ ์ฌ์ฉํ๋ฉด ๋ถํ์ํ ๋ณต์ฌ๊ฐ ํํด์ง๋ ์ฑ๋ฅ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
๋ด๋ถ์ ํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ์ ๋น์ทํ ๊ฐ์ฒด๋ฅผ ์ ์ ํ ์ฌ์ฉํ๋ฉด ๋ถํ์ํ ๋ณต์ฌ๊ฐ ํํด์ง๋ ์ฑ๋ฅ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
๋ง์ฝ ๊ฐ์ฒด x๊ฐ y๋ฅผ ๊ฐ๋ฆฌํจ๋ค๋ฉด x๋ฅผ ๋ณต์ฌํ๋ค๊ณ ํด์ y๋ ๋ณผ์ฌ๋ ๊น?
๋ง์ฝ y๊ฐ x์ ๋ฉค๋ฒ๋ผ๋ฉด ์ด๋ ์ณ๋ค. ๊ทธ๋ ์ง๋ง ์ด์ฉ๋ค๊ฐ y๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ๋ ๊ฒฝ์ฐ๋ผ๋ฉด ์ด๋ ์ณ์ง ์๋ค.
๋ง์ฝ y๊ฐ x์ ๋ฉค๋ฒ๋ผ๋ฉด ์ด๋ ์ณ๋ค. ๊ทธ๋ ์ง๋ง ์ด์ฉ๋ค๊ฐ y๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ๋ ๊ฒฝ์ฐ๋ผ๋ฉด ์ด๋ ์ณ์ง ์๋ค.
์ด์ฅ์ ๋ด์ฉ์ ์๋นํ ์ถ์์ ์ด๊ธฐ ๋๋ฌธ์ ์๋นํ ์ฃผ์ ๊น์ ์ดํด๊ฐ ํ์ํ๋ค.
1.1. 14.1 Handles that copy their objects ¶
13์ฅ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ์ํด์๋ ์๋ก ๋ค๋ฅธ ํ์
์ ๊ฐ์ฒด๋ฅผ ํ๊ฐ์ ์ปฌ๋ ์
์ ์ ํ๋ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค.
13.3.1์ ์ ์ฒซ๋ฒ์งธ ํด๊ฒฐ๋ฒ์์ ๋ ์ด๋ฅผ ์ํด์ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ์ฌ์ Core ํน์ Core๋ก ๋ถํฐ ํ์๋ ๊ฐ์ฒด๋ค์ ์์ฑํ์ฌ ์ปฌ๋ ์ ๋ด๋ถ์ ํฌ์ธํฐ๋ค๋ก ๊ฐ๋ฆฌํค๋๋ก ํ์๋ค. ๋ฐ๋ผ์ ์ด ๊ฒฝ์ฐ ์ฌ์ฉ์ ์ฝ๋๋ ๊ฐ์ฒด์ ๋์ ์์ฑ, ํด์ ์ ๊ด๋ จ๋ ๊ฒ๋ค์ ์ฒ๋ฆฌํ ์ฑ ์์ด ์์๋ค.
13.3.1์ ์ ์ฒซ๋ฒ์งธ ํด๊ฒฐ๋ฒ์์ ๋ ์ด๋ฅผ ์ํด์ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ์ฌ์ Core ํน์ Core๋ก ๋ถํฐ ํ์๋ ๊ฐ์ฒด๋ค์ ์์ฑํ์ฌ ์ปฌ๋ ์ ๋ด๋ถ์ ํฌ์ธํฐ๋ค๋ก ๊ฐ๋ฆฌํค๋๋ก ํ์๋ค. ๋ฐ๋ผ์ ์ด ๊ฒฝ์ฐ ์ฌ์ฉ์ ์ฝ๋๋ ๊ฐ์ฒด์ ๋์ ์์ฑ, ํด์ ์ ๊ด๋ จ๋ ๊ฒ๋ค์ ์ฒ๋ฆฌํ ์ฑ ์์ด ์์๋ค.
์ ์์ค ์๋ฃ๊ตฌ์กฐ์ธ ํฌ์ธํฐ๋ฅผ ์ง์ ์์ํจ์ผ๋ก์ ์๊ธฐ๋ ๋ฌธ์ ์
๋ง์ง๋ง 2๊ฐ์ง์ ๊ฒฝ์ฐ๋ ๊ทธ ํฌ์ธํฐ๋ฅผ ๋ค๋ฅธ ๊ณณ์์ ์ฐธ์กฐํ ๊ฒฝ์ฐ ์ด๋ค ์ผ์ด ์ผ์ด๋ ์ง ์ ์ ์๋ค.
* ํฌ์ธํฐ๋ฅผ ๋ณต์ฌํ๋ ๊ฒ์ ๊ทธ ๋์ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๋ ๊ฒ๊ณผ๋ ๋ค๋ฆ. * ํฌ์ธํฐ์ ์๋ฉธ์ด ๊ทธ ๊ฐ์ฒด์ ์๋ฉธ์ ์๋ฏธํ์ง ์๋๋ค. (memory leak) * ํฌ์ธํฐ ์๋ฉธ์ํค์ง ์๊ณ , ๊ฐ์ฒด๋ฅผ ์๋ฉธํ ๊ฒฝ์ฐ dangling pointer ๋ฐ์. * ํฌ์ธํฐ ์์ฑ์ ์ด๊ธฐํํ์ง ์์ผ๋ฉด, ํฌ์ธํฐ๋ฅผ ๋ฐ์ธ๋ฉ๋์ง ์์ ์ํ๊ฐ๋๋ค. |
13.5์ Student_info ๋ ํ๋ก๊ทธ๋๋จธ๊ฐ ๋ด๋ถ์ Core๊ฐ์ฒด๋ฅผ ๋ณผ ์์๊ณ , ์๋์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๊ฐ ๋๋๋ก์ ํ์ผ๋, ๋ฉ์๋๋ค์ด Coreํด๋์ค์ public์ฐ์ฐ๋ค์ ๊ทธ๋๋ก ๋ฐ๋ฅด๋ ๊ฒ๋ค์ด ๋ง๋ค.
์ด์ฅ์์๋ ์ด๋ฐ ํธ๋ค(handle)ํด๋์ค๋ฅผ ์ผ๋ฐ์ ์ธ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ ์๊ฒ ๋๋ค.
์ด์ฅ์์๋ ์ด๋ฐ ํธ๋ค(handle)ํด๋์ค๋ฅผ ์ผ๋ฐ์ ์ธ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ ์๊ฒ ๋๋ค.
1.1.1. 14.1.1 ์ ๋ค๋ฆญ ํธ๋ค ํด๋์ค(generic handle class) ¶
์ด ํด๋์ค๋ ๊ฐ์ฒด์ ํ์ ๋ฌด๊ดํ๊ฒ ๋์ํ์ฌ์ผ ํ๋ฏ๋ก ํ
ํ๋ฆฟ์ผ๋ก ์์ฑํ๋ค.
Handle ํด๋์ค์ ์๊ตฌ์ฌํญ
์ฌ์ฉ์๊ฐ Handle ํด๋์ค๋ฅผ ์ด์ฉํด์ ํน์ ํ ๊ฐ์ฒด์ Handle์ ๋ถ์ด๊ฒ ๋๋ฉด Handle์ ๊ทธ ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌํ๊ฒ ๋๋ค.
๋์ ์ผ๋จ ๊ทธ ๊ฐ์ฒด๋ ์ค์ง ํ๋์ Handle๋ง์ ๋ถ์ฐฉ์์ผ์ผ ํ๋ฉฐ, ์ผ๋จ ๋ถ์ฐฉ์ํจ ๋ค์๋ ํฌ์ธํฐ๊ฐ์๋ Handle์ ์ด์ํด์ ๊ฐ์ฒด์ ์ ๊ทผํด์ผํ๋ค.
์ฆ Handle์ด ์๋ฉธ๋๋ฉด Handle์ด ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๋ ์๋ฉธ๋๊ฒ ๋๋ค. ์ฌ์ฉ์๋ ๋ฐ์ธ๋ฉ์ด ์๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํธ๋ค์ ๋ง๋ค์๋ ์์ง๋ง ์ด ๊ฒฝ์ฐ ํธ๋ค์ ์ ๊ทผํ๊ฒ๋๋ฉด ์์ธ ์ํฉ์ ๋ฐ์ํ๊ฒ๋๋ค. (์๋๋ฉด ์ฒ์ ์์ฑ์ ๊ฐ์ฒด๊ฐ ๋ฐ์ธ๋ฉ ๋์ด์๋์ง๋ฅผ ๊ฒ์ฌํ๋๋ก ํ๋ฉด ๋๋ค.)
Handle ํด๋์ค์ ์๊ตฌ์ฌํญ
* Handle์ ๊ฐ์ฒด์ ์ฐธ์กฐ๊ฐ * Handle์ ๋ณต์ฌ๊ฐ ๊ฐ๋ฅํ๋ค * Handle ๊ฐ์ฒด๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ฐ์ธ๋ฉ๋์ด ์๋์ง ํ์ธ์ด ๊ฐ๋ฅ * Handleํด๋์ค๊ฐ ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๊ฐ ์์๊ตฌ์กฐ์ ํด๋์คํ์ ๊ฐ๋ฆฌํจ๋ค๋ฉด virtual ์ ์ํด ์ง์ ๋ ์ฐ์ฐ์๋ํด์ ๋คํ์ฑ์ ์ ๊ณตํ๋ค. |
์ฌ์ฉ์๊ฐ Handle ํด๋์ค๋ฅผ ์ด์ฉํด์ ํน์ ํ ๊ฐ์ฒด์ Handle์ ๋ถ์ด๊ฒ ๋๋ฉด Handle์ ๊ทธ ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌํ๊ฒ ๋๋ค.
๋์ ์ผ๋จ ๊ทธ ๊ฐ์ฒด๋ ์ค์ง ํ๋์ Handle๋ง์ ๋ถ์ฐฉ์์ผ์ผ ํ๋ฉฐ, ์ผ๋จ ๋ถ์ฐฉ์ํจ ๋ค์๋ ํฌ์ธํฐ๊ฐ์๋ Handle์ ์ด์ํด์ ๊ฐ์ฒด์ ์ ๊ทผํด์ผํ๋ค.
์ฆ Handle์ด ์๋ฉธ๋๋ฉด Handle์ด ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๋ ์๋ฉธ๋๊ฒ ๋๋ค. ์ฌ์ฉ์๋ ๋ฐ์ธ๋ฉ์ด ์๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํธ๋ค์ ๋ง๋ค์๋ ์์ง๋ง ์ด ๊ฒฝ์ฐ ํธ๋ค์ ์ ๊ทผํ๊ฒ๋๋ฉด ์์ธ ์ํฉ์ ๋ฐ์ํ๊ฒ๋๋ค. (์๋๋ฉด ์ฒ์ ์์ฑ์ ๊ฐ์ฒด๊ฐ ๋ฐ์ธ๋ฉ ๋์ด์๋์ง๋ฅผ ๊ฒ์ฌํ๋๋ก ํ๋ฉด ๋๋ค.)
~cpp template <class T> class Handle { public: Handle(): p(0) { } // ๊ธฐ๋ณธ์์ฑ์๋ ๋ด๋ถ ๋ฉค๋ฒ๋ฅผ 0์ผ๋ก ์ด๊ธฐํํ์ฌ์ ์์ง ๋ฐ์ธ๋ฉ์ด ์๋ ์ํ์์ ๋ํ๋ธ๋ค. Handle(const Handle& s) : p(0) { if (s.p) p = s.p->clone(); } // ๋ณต์ฌ ์์ฑ์๋ ์ธ์๋ก ๋ฐ์ ๊ฐ์ฒด์ clone() ํจ์๋ฅผ ํตํด์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ทธ ๊ฒ์ ๋์ ํ๋ค. Handle& operator=(const Handle&); ~Handle() { delete p; } Handle(T* t):p(t) { } operator bool() const { return p; } T& operator*() const; T* operator->() const; private: T* p; }; template<class T> Handle<T>& Handle<T>::operator=(const Handle& rhs) { if(&rhs != this) { // ์๊ธฐ ์ฐธ์กฐ๋ฅผ ์กฐ์ฌํ๋ค ํ๋๋ฐฉ์์ ๊ฒฐ์ ํ๋ค. delete p; p = rhs.p ? rhs.p->clone() : 0; } return *this; }
~cpp Handle<Core> p(new Grad); // Handle<Core> == Core* // Handle<Core> ๋ ์๋ก ์์ฑ๋ Grad๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
~cpp template<class T> T& Handle<T>::operator*() const { if(p) return *p; throw runtime_error("unbound Handle"); } // ์ต๊ธฐํ๋ฅผ ํ ๋ ์์ฑํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค. template<class T> T* Handle<T>::operator->() const { if(p) return p; throw runtime_error("unbound Handle"); }-> ์ฐ์ฐ์๋ ์ผ๊ฒฌ ์ดํญ ์ฐ์ฐ์ ์ฒ๋ผ ๋ณด์ด์ง๋ง ๋์ํ๋ ๋ฐฉ์์ด ๋ค๋ฅธ ์ฐ์ฐ์๋ค๊ณผ๋ ๋ค๋ฅด๋ค. ->๋ฅผ ํธ์ถํ๊ฒ ๋๋ฉด ์ฐ์ฐ์์ ์ข์ธก์์์์ ํฌ์ธํฐ๋ฅผ ๋์ ํด์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ ์์๊ฐ ๋ฆฌํด๋๋ค.
~cpp // ๋์ผํ ํํ x->y; (x.operator->())->y; //as upper student->y; (student.operator->())->y; student.p->y;์๊ธฐ์ ์ ์์์ *, -> ์ฐ์ฐ์๋ฅผ ์ฐธ์กฐํ, ํฌ์ธํฐํ์ผ๋ก ๋ฆฌํดํ๊ฒ ํจ์ผ๋ก์จ ์๋์ผ๋ก ํ์๊ฐ์ฒด์ ๋ํ ๋์ ๋ฐ์ธ๋ฉ์ด ๊ฐ๋ฅํด ์ง๋ค.
1.1.2. 14.1.2 ์ ๋ค๋ฆญ ํธ๋ค ์ฌ์ฉํ๊ธฐ ¶
~cpp //main.cpp #include <algorithm> #include <ios> #include <iomanip> #include <iostream> #include <stdexcept> #include <vector> #include "Handle.h" #include "Student_info.h" using std::cin; using std::cout; using std::domain_error; using std::endl; using std::sort; using std::streamsize; using std::setprecision; using std::setw; using std::string; using std::vector; using std::max; bool compare_Core_handles(const Handle<Core>& lhs, const Handle<Core>& rhs) { return compare(*lhs, *rhs); } int main() { vector< Handle<Core> > students; // changed type Handle<Core> record; // changed type char ch; string::size_type maxlen = 0; // read and store the data while (cin >> ch) { if (ch == 'U') record = new Core; // allocate a `Core' object else record = new Grad; // allocate a `Grad' object record->read(cin); // `Handle<T>::->', then `virtual' call to `read' maxlen = max(maxlen, record->name().size()); // `Handle<T>::->' students.push_back(record); } // `compare' must be rewritten to work on `const Handle<Core>&' sort(students.begin(), students.end(), compare_Core_handles); // write the names and grades for (vector< Handle<Core> >::size_type i = 0; i != students.size(); ++i) { // `students[i]' is a `Handle', which we dereference to call the functions cout << students[i]->name() << string(maxlen + 1 - students[i]->name().size(), ' '); try { double final_grade = students[i]->grade(); streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error e) { cout << e.what() << endl; } // no `delete' statement } return 0; }Handle ํด๋์ค๋ ์ฐ๊ฒฐ๋ ๊ฐ์ฒด์ clone() ๋ฉค๋ฒํจ์๋ฅผ ์ด์ฉํ๋ค. ๋ฐ๋ผ์ Coreํด๋์ค์ clone()๋ฉ์๋๋ฅผ public์ผ๋ก ์์ฑํ๋ ๊ฒ์ด ํ์ํ๋ค.
Handle<>์ ์ด์ฉํ Student_info ์ ๊ตฌํ
~cpp //Student_info.h #ifndef GUARD_Student_info #define GUARD_Student_info #include <iostream> #include <string> #include "Core.h" #include "Handle.h" class Student_info { public: Student_info() { } Student_info(std::istream& is) { read(is); } // no copy, assign, or destructor: they're no longer needed std::istream& read(std::istream&); std::string name() const { if (cp) return cp->name(); else throw std::runtime_error("uninitialized Student"); } double grade() const { if (cp) return cp->grade(); else throw std::runtime_error("uninitialized Student"); } static bool compare(const Student_info& s1, const Student_info& s2) { return s1.name() < s2.name(); } private: Handle<Core> cp; // Handle ํด๋์ค๊ฐ ์์ฑ๊ณผ ์๋ฉธ์ ์๋ํํ๊ธฐ ๋๋ฌธ์ ๋ณต์ฌ ์์ฑ์, ๋์ ์ฐ์ฐ์, ์๋ฉธ์๊ฐ ํ์ ์๋ค. }; #endif
Student_info::read ์ ์ฌ์ ์
~cpp //Student_info.cpp #include <iostream> #include "Student_info.h" #include "Core.h" using std::istream; istream& Student_info::read(istream& is) { char ch; is >> ch; // get record type // allocate new object of the appropriate type // use `Handle<T>(T*)' to build a `Handle<Core>' from the pointer to that object // call `Handle<T>::operator=' to assign the `Handle<Core>' to the left-hand side if (ch == 'U') cp = new Core(is); else cp = new Grad(is); return is; }์๋์ผ๋ก ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๊ฐ ๋๊ธฐ ๋๋ฌธ์ delete ๊ตฌ๋ฌธ์ ์ ๊ฑฐํจ. Handle::operator=()์ ๋ด๋ถ ๋ฉ๋ชจ๋ฆฌ์ ํด์ ๊ตฌ๋ฌธ์ด ๋ค์ด์๊ธฐ ๋๋ฌธ์ ๋ถํ์.
1.2. 14.2 Reference-counted handles ¶
์ด๋ค ๊ฒฝ์ฐ์ ํ๋ก๊ทธ๋๋จธ๋ Handle์ด ๋์ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๋ ํํ๊ฐ ์๋๋ผ ๋จ์ง ๊ฐ๋ฆฌํค๋ ํํ๋ก๋ง ์ฌ์ฉ๋๊ธฐ๋ฅผ ๋ฐ๋ ์ ์๋ค. ์ฆ ๋์ผํ ๊ฐ์ฒด๋ฅผ 2๊ฐ์ ๋ค๋ฅธ Handle ์ด ๊ฐ๋ฆฌํฌ ์ ์๋ค๋ ๋ง์ด๋ค.
์ด๊ฒฝ์ฐ ๋์๊ฐ์ฒด์ ํด์ ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ง์ง๋ง ํธ๋ค์ด ์๋ฉธ๋ ๋ ํํด์ ธ์ผํ๋ค. ์ด๋ฅผ ์ํด ๋ ํผ๋ฐ์ค ์นด์ดํธ(reference count, ์ฐธ์กฐ๊ณ์)๋ฅผ ์ฌ์ฉํ๋ค.
์ด๋ฅผ ์ํด์ ์ฐ๋ฆฌ๋ ์ด์ ์ ํด๋์ค์ ์นด์ดํฐ(counter, ๊ณ์๊ธฐ)๋ฅผ ์ถ๊ฐํ๊ณ ๊ฐ์ฒด์ ์์ฑ, ๋ณต์ฌ, ์๋ฉธ์ ์ด ์นด์ดํฐ๋ฅผ ์ ์ ํ๊ฒ ๊ฐฑ์ ํ๋ค.
์ด๊ฒฝ์ฐ ๋์๊ฐ์ฒด์ ํด์ ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ง์ง๋ง ํธ๋ค์ด ์๋ฉธ๋ ๋ ํํด์ ธ์ผํ๋ค. ์ด๋ฅผ ์ํด ๋ ํผ๋ฐ์ค ์นด์ดํธ(reference count, ์ฐธ์กฐ๊ณ์)๋ฅผ ์ฌ์ฉํ๋ค.
์ด๋ฅผ ์ํด์ ์ฐ๋ฆฌ๋ ์ด์ ์ ํด๋์ค์ ์นด์ดํฐ(counter, ๊ณ์๊ธฐ)๋ฅผ ์ถ๊ฐํ๊ณ ๊ฐ์ฒด์ ์์ฑ, ๋ณต์ฌ, ์๋ฉธ์ ์ด ์นด์ดํฐ๋ฅผ ์ ์ ํ๊ฒ ๊ฐฑ์ ํ๋ค.
~cpp //Ref_handle.h #ifndef Ref_handle_h #define Ref_handle_h #include <cstddef> #include <stdexcept> template <class T> class Ref_handle { public: // manage reference count as well as pointer Ref_handle(): p(0), refptr(new size_t(1)) { } Ref_handle(T* t): p(t), refptr(new size_t(1)) { } Ref_handle(const Ref_handle& h): p(h.p), refptr(h.refptr) { ++*refptr; } // ์ฐธ์กฐํ์ผ๋ก ๋์ํ๋ Handle์ธ๊ฒฝ์ฐ. ์นด์ดํฐ์ ์ฃผ์๋ฅผ ๋์๊ฐ์ฒด์ ์นด์ดํฐ์ ์ฃผ์๋ก ์ด๊ธฐํ, ์นด์ดํฐ๋ฅผ ์ฆ๊ฐ์ํจ๋ค. Ref_handle& operator=(const Ref_handle&); ~Ref_handle(); // as before operator bool() const { return p; } T& operator*() const { if (p) return *p; throw std::runtime_error("unbound Ref_handle"); } T* operator->() const { if (p) return p; throw std::runtime_error("unbound Ref_handle"); } private: T* p; std::size_t* refptr; // added }; template <class T> Ref_handle<T>& Ref_handle<T>::operator=(const Ref_handle& rhs) { // Ref_handle&๋ฅผ ์ธ์๋ก๊ฐ๋ ์์ฑ์์ ๋ง์ฐฌ๊ฐ์ง๋ก operator= ๋ ์ธ์๋ก ๋ฐ์ ๋์์ด Ref_handle ์ธ ๊ฒฝ์ฐ ์นด์ดํฐ๋ฅผ ํ๋ ์ฆ๊ฐ์ํจ๋ค. ++*rhs.refptr; // free the left-hand side, destroying pointers if appropriate // ์ฌ๊ธฐ์ ๋ง์ฝ ์๊ธฐ ์์ ์ ๋์ ํ ๊ฒฝ์ฐ์๋ ๊ฐ์ฒด์ ์ฐธ์กฐ์ ์นด์ดํฐ๊ฐ ๋ณํํ์ง ์๊ฒ๋๋ค. if (--*refptr == 0) { delete refptr; delete p; } // ๋ง์ง๋ง ๋์๊ฐ์ฒด์ ํธ๋ค์ด๋ผ๋ฉด ํ์ฌ ์กด์ฌํ๋ ๋์ ๊ฐ์ฒด๋ฅผ ์ญ์ // copy in values from the right-hand side refptr = rhs.refptr; p = rhs.p; return *this; } template <class T> Ref_handle<T>::~Ref_handle() { if (--*refptr == 0) { delete refptr; delete p; } } // ์๋ฉธ๋๋ ํธ๋ค์ด ๋์๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ง์ง๋ง ๊ฐ์ฒด๋ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ์์ ํด์ // refptr๋ ๋์ ํ ๋น๋ ๊ฐ์ฒด์ด๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ํด์ฃผ๋ ์ฝ๋๊ฐ ํ์ํ๋ค. #endif
๋ฌธ์ ์
~cpp //Ref_handle์ ๊ธฐ๋ฐ์ผ๋ก ์์ฑ๋ Student_info ํด๋์ค์ ์ฌ์ฉ์ Student_info s1(cin); Student_info s2 = s1; // s1์ ๊ฐ์ s2๋ก ๋ณต์ฌํ๋ค. ํ์ง๋ง ๋ด๋ถ์ ๊ฐ์ฒด๋ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํจ๋ค.ํ์์๋ ๋ณต์ฌ๋ ์ผ์ด๋์ง ์์ง๋ง ์ด ๊ฒฝ์ฐ ํ๋ก๊ทธ๋๋จธ๊ฐ ์์น ์์ ๊ฒฝ์ฐ์๋ ๋์ผํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ์ผ์ด ๋ฐ์ํ๋ค.
1.3. 14.3 Handles that let you decide when to share data ¶
~cpp //ptr.h #ifndef GUARD_Ptr_h #define GUARD_Ptr_h #include <cstddef> #include <stdexcept> template <class T> class Ptr { public: // new member to copy the object conditionally when needed void make_unique() { if (*refptr != 1) { --*refptr; refptr = new size_t(1); p = p? clone(p): 0; } } /* ์ด ํจ์๋ ํ๋ก๊ทธ๋๋จธ๊ฐ ํ์ํ ๋ ํ์ฌ ๊ฐ๋ฆฌํค๋ ๋ด๋ถ๊ฐ์ฒด์ ๋์ผํ ๋ด์ฉ์ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ค๋ค. ๋์ ์ ๊ฐ๋ฆฌํค๋ ๋์์ ํธ๋ค์ด 1๊ฐ์ธ ๊ฒฝ์ฐ์๋ ์ด๋ฐ ๋ณต์ฌ๋ฅผ ํํ์ง ์๋๋ค. */ // the rest of the class looks like `Ref_handle' except for its name Ptr(): p(0), refptr(new size_t(1)) { } Ptr(T* t): p(t), refptr(new size_t(1)) { } Ptr(const Ptr& h): p(h.p), refptr(h.refptr) { ++*refptr; } Ptr& operator=(const Ptr&); // implemented analogously to 14.2/261 ~Ptr(); // implemented analogously to 14.2/262 operator bool() const { return p; } T& operator*() const; // implemented analogously to 14.2/261 T* operator->() const; // implemented analogously to 14.2/261 private: T* p; std::size_t* refptr; }; template <class T> T* clone(const T* tp) { return tp->clone(); } template<class T> T& Ptr<T>::operator*() const { if (p) return *p; throw std::runtime_error("unbound Ptr"); } template<class T> T* Ptr<T>::operator->() const { if (p) return p; throw std::runtime_error("unbound Ptr"); } template<class T> Ptr<T>& Ptr<T>::operator=(const Ptr& rhs) { ++*rhs.refptr; // \f2free the lhs, destroying pointers if appropriate\fP if (--*refptr == 0) { delete refptr; delete p; } // \f2copy in values from the right-hand side\fP refptr = rhs.refptr; p = rhs.p; return *this; } template<class T> Ptr<T>::~Ptr() { if (--*refptr == 0) { delete refptr; delete p; } } #endif
์ด ๊ตฌ์กฐ๋ฅผ ์ด์ฉํด์ Student_info๋ฅผ ์์ฑํ๋ ๊ฒฝ์ฐ ์ฐ๋ฆฌ๋ ์๋ก ์ด ํด๋์ค์ ๋ํด์ ์์ฑํ ์ฝ๋๊ฐ ์ ํ์๋ค.
์๋ํ๋ฉด Student_info์ ๋ํด์ ๋ด๋ถ ๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ๋ ํจ์๋ ์ค์ง read์ธ๋ฐ ์ฐ๋ฆฌ์ ๊ฒฝ์ฐ์๋ read ํจ์ ํธ์ถ์ ๊ธฐ์กด์ ๋ด๋ถ ๋ฉค๋ฒ๋ฅผ ์๋ฉธ์ํค๊ณ , ๋ค์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ํ ๋นํ๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ํ๋ฉด Student_info์ ๋ํด์ ๋ด๋ถ ๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ๋ ํจ์๋ ์ค์ง read์ธ๋ฐ ์ฐ๋ฆฌ์ ๊ฒฝ์ฐ์๋ read ํจ์ ํธ์ถ์ ๊ธฐ์กด์ ๋ด๋ถ ๋ฉค๋ฒ๋ฅผ ์๋ฉธ์ํค๊ณ , ๋ค์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ํ ๋นํ๊ธฐ ๋๋ฌธ์ด๋ค.
~cpp Student_info s1; s1.read(cin); Student_info s2 = s1; s2.read(cin)๊ทธ๋ฐ๋ฐ ๋ด๋ถ๊ฐ์ฒด์ธ Ptr ํธ๋ค์ ๊ทธ ์์๋ฅผ ๋ํ๋ด๋ ํธ๋ค์ด ์ค์ง 1๊ฐ์ผ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด ๋์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํ์ง ์๊ธฐ ๋๋ฌธ์ ์๋์ ๊ฐ์ ์ฝ๋์์ s1, s2์ ๊ฐ์ ๋ณํ๊ฐ ์ํธ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ค.
ํธ์ถ ๊ฐ์ฒด์ ๋ณํ๊ฐ ๊ฐ์ ์์๋ฅผ ๊ฐ๋ฆฌํค๋ ํธ๋ค๋ค์๊ฒ ์ํฅ์ ์ฃผ์ง์๊ธฐ๋ฅผ ๋ฐ๋ผ๋ regrade ํจ์
~cpp void Student_info::regrade(double final, double thesis) { cp.make_unique(); if(cp) cp->regrade(final, thesis); else throw run_time_error("regrade of unknown student"); }
1.4. 14.4 An improvement on controllable handles ¶
~cpp //Str.h - ์น๊ธฐ๊ฐ ๊ท์ฐฎ์์ ๊ทธ๋ฅ ๋ณต์ฌํจ. -_- #ifndef GUARD_Str_h #define GUARD_Str_h #include <algorithm> #include <iostream> #include "Ptr.h" #include "Vec.h" template<> Vec<char>* clone(const Vec<char>*); // does this version work? class Str { friend std::istream& operator>>(std::istream&, Str&); friend std::istream& getline(std::istream&, Str&); public: Str& operator+=(const Str& s) { data.make_unique(); std::copy(s.data->begin(), s.data->end(), std::back_inserter(*data)); return *this; } // interface as before typedef Vec<char>::size_type size_type; // reimplement constructors to create `Ptr's Str(): data(new Vec<char>) { } Str(const char* cp): data(new Vec<char>) { std::copy(cp, cp + std::strlen(cp), std::back_inserter(*data)); } Str(size_type n, char c): data(new Vec<char>(n, c)) { } template <class In> Str(In i, In j): data(new Vec<char>) { std::copy(i, j, std::back_inserter(*data)); } // call `make_unique' as necessary char& operator[](size_type i) { data.make_unique(); return (*data)[i]; } const char& operator[](size_type i) const { return (*data)[i]; } size_type size() const { return data->size(); } typedef char* iterator; typedef const char* const_iterator; iterator begin() { return data->begin(); } const_iterator begin() const { return data->begin(); } iterator end() { return data->end(); } const_iterator end() const { return data->end(); } private: // store a `Ptr' to a `vector' Ptr< Vec<char> > data; }; // as implemented in 12.3.2/216 and 12.3.3/219 std::ostream& operator<<(std::ostream&, const Str&); Str operator+(const Str&, const Str&); inline bool operator<(const Str& lhs, const Str& rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } inline bool operator>(const Str& lhs, const Str& rhs) { return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end()); } inline bool operator<=(const Str& lhs, const Str& rhs) { return !std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end()); } inline bool operator>=(const Str& lhs, const Str& rhs) { return !std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } inline bool operator==(const Str& lhs, const Str& rhs) { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); } inline bool operator!=(const Str& lhs, const Str& rhs) { return !(lhs == rhs); } #endif
๊ธฐ๋ณธ ์ธํฐํ์ด์ค๋ ์ด์ ์ Str๊ณผ ๋์ผํ์ง๋ง ์๋ฃ๊ตฌ์กฐ๊ฐ Ptr< Vec<char> > ํ์ผ๋ก ์ ์๋์๊ธฐ ๋๋ฌธ์ ์ ์ฒด์ ์ธ ๋ฉ์๋์ ์ธ๋ถ ๊ตฌํ์ด ๋ง์ด ๋ณ๊ฒฝ๋์๋ค. ๊ทธ๋ฆฌ๊ณ Ptrํ
ํ๋ฆฟ์ผ๋ก ์๋ฃ๊ตฌ์กฐ๋ฅผ ๋ค๋ฃธ์ผ๋ก์ Strํด๋์ค๊ฐ ๋์ผํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํฌ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
1.4.1. 14.4.1 ์ ์ดํ ์ ์๋ ํ์ ๋ณต์ฌํ๊ธฐ ¶
~cpp template<class T> void Ptr<T>::make_unique() { if(*refptr != 1) { --*refptr; refptf = new size_t(1); p = p? p->clone() : 0; } }์ด ๊ตฌํ์ ์ํด์๋ Vec::clone()๊ฐ ์ ์๋์ด ์์ด์ผํ์ง๋ง, ์ด ํจ์๋ฅผ ์ ์ํ๊ฒ ๋ ๊ฒฝ์ฐ ์๋ Vec์ ๊ตฌํ์ด ํ์ค ํจ์ vector์ ๊ตฌํ์ ๋ถ๋ถ์ด๋ผ๋ ๊ฐ์ ์์ ์๋ฐฐ๋๊ธฐ ๋๋ฌธ์ ์ถ๊ฐํ ์๋ ์๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์ฐ๋ฆฌ๋ ์ ์ญํจ์์ธ clone()๋ฅผ ๋ง๋ค์ด์ ํด๊ฒฐํ๋ค. (์ํํธ์จ์ด ๊ณตํ์์๋ ํ๋จ๊ณ๋ฅผ ์ฐํํ๋ฉด ๋ชจ๋ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋๋ค๋ผ๋ ๋ง์ด ์๋๋ฐ ์ฌ๊ธฐ์ ์ ์ฉ๋ ์ ์๋ค,)
~cpp template<class T> void Ptr<T>::make_unique() { if(*refptr != 1) { --*refptr; refptf = new size_t(1); p = p? clone() : 0; } }
::clone()์ ๊ตฌํ
~cpp template<> Vec<char*> clone(const Vec<char>* vp) { return new Vec<char>(*vp); }ํ ํ๋ฆฟ์ ๊ตฌ์ฒดํ(template specialization)
template<>๋ฅผ ์ฌ์ฉํ๋ฉด ํน์ ์ธ์ ํ์ ์ ๋ํ ํน์ ํ ํ๋ฆฟ ํจ์์ ๋ฒ์ ์ ์ ์ํ๋ค.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง ํจ์๋ ๋ง์ฝ Vec<char>*๊ฐ ์ธ์๋ก ์ค๋ ๊ฒฝ์ฐ์๋ ์ด ๊ฒ์ด ์คํ๋๊ณ ๋ค๋ฅธ ๋ฒ์ ์ ํ ํ๋ฆฟ์ด ์ค๋ ๊ฒฝ์ฐ์๋ ๊ทธ ๊ฐ์ฒด์ clone()๋ฒ์ ์ ์คํํ๊ฒ ๋๋ค.
์ด๋ฌํ ์ฌํญ์ ์์ฝํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค
* Ptr<T>::make_unique()๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด T::clone์ ๋ถํ์ * Ptr<T>::make_unique๋ฅผ ์ฌ์ฉํ๋ค๋ฉด T::clone๊ฐ ์๋ค๋ฉด T::clone์ ์ฌ์ฉํ ๊ฒ์ด๋ค. * Ptr<T>::make_unique๋ฅผ ์ฌ์ฉํ๋ค๋ฉด T::clone๊ฐ ๋ฏธ์ ์๋์๋ค๋ฉด clone<T>๋ฅผ ์ ์ํด์ ์ํ๋ ๋ฐ๋ฅผ ์ป์ ์ ์๋ค. |
1.4.2. 14.4.2 ์ธ์ ๋ณต์ฌ๊ฐ ํ์ํ ๊น์? ¶
๋ง์ฝ const ๊ฐ์ฒด๋ฅผ ํตํด์ operator[]๋ฅผ ํตํด์ ์ ๊ทผํ๋ค๋ฉด ๊ฐ์ฒด์ ๋ด์ฉ์ ๋ฐ๊พธ๋ ๊ฒ์ ํ์ฉํด์๋ ์๋๋ค.
์ด๋ด๊ฒฝ์ฐ operator[] const๋ฅผ ํตํด์ ๋ฆฌํด๋๋ ๊ฐ์ make_unique๋ฅผ ํตํด์ ๋ณต์ฌ๋ ๊ฒ์ ๋ฆฌํดํจ์ผ๋ก์ ์๋ณธ ๊ฐ์ฒด์ ๋ฐ์ดํฐ์ ๋ณํ์ ๋ฐฉ์งํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.
์ด๋ด๊ฒฝ์ฐ operator[] const๋ฅผ ํตํด์ ๋ฆฌํด๋๋ ๊ฐ์ make_unique๋ฅผ ํตํด์ ๋ณต์ฌ๋ ๊ฒ์ ๋ฆฌํดํจ์ผ๋ก์ ์๋ณธ ๊ฐ์ฒด์ ๋ฐ์ดํฐ์ ๋ณํ์ ๋ฐฉ์งํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.