U E D R , A S I H C RSS

AcceleratedC++/Chapter14

1. Chapter 14 Managing memory (almost) automatically

Student_info ํด๋ž˜์Šค๋Š” ๋ ˆ์ฝ”๋“œ์˜ ์ธํ„ฐํŽ˜์ด์Šค. ๋ ˆ์ฝ”๋“œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๊ด€๋ฆฌํ•œ๋‹ค.
์ด๋ ‡๊ฒŒ 2๊ฐ€์ง€์˜ ์ถ”์ƒ์ ์ธ ๊ธฐ๋Šฅ์„ ์กฐํ•ฉํ•ด์„œ ๋งŒ๋“ค๊ฒŒ ๋˜๋Š” ๊ฒƒ์€ ํ—ˆ์ˆ ํ•œ ํด๋ž˜์Šค ์„ค๊ณ„๋•Œ๋ฌธ์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

์ด ์žฅ์—์„œ๋Š” ํฌ์ธํ„ฐ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜์ง€๋งŒ, ์ž์ฒด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
๋‚ด๋ถ€์˜ ํ•œ ๊ฐœ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ์™€ ๋น„์Šทํ•œ ๊ฐ์ฒด๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ๋ณต์‚ฌ๊ฐ€ ํ–‰ํ•ด์ง€๋Š” ์„ฑ๋Šฅ์ƒ์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ๊ฐ์ฒด x๊ฐ€ y๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค๋ฉด x๋ฅผ ๋ณต์‚ฌํ•œ๋‹ค๊ณ  ํ•ด์„œ y๋„ ๋ณผ์‚ฌ๋ ๊นŒ?
๋งŒ์•ฝ y๊ฐ€ x์˜ ๋ฉค๋ฒ„๋ผ๋ฉด ์ด๋Š” ์˜ณ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ ์–ด์ฉŒ๋‹ค๊ฐ€ y๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋œ ๊ฒฝ์šฐ๋ผ๋ฉด ์ด๋Š” ์˜ณ์ง€ ์•Š๋‹ค.

์ด์žฅ์˜ ๋‚ด์šฉ์€ ์ƒ๋‹นํžˆ ์ถ”์ƒ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋‹นํžˆ ์ฃผ์˜ ๊นŠ์€ ์ดํ•ด๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

1.1. 14.1 Handles that copy their objects

13์žฅ์—์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ์œ„ํ•ด์„œ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ํ•œ๊ฐœ์˜ ์ปฌ๋ ‰์…˜์— ์ –ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ–ˆ๋‹ค.
13.3.1์ ˆ์˜ ์ฒซ๋ฒˆ์งธ ํ•ด๊ฒฐ๋ฒ•์—์„ ๋А ์ด๋ฅผ ์œ„ํ•ด์„œ ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ์„œ Core ํ˜น์€ Core๋กœ ๋ถ€ํ„ฐ ํŒŒ์ƒ๋œ ๊ฐ์ฒด๋“ค์„ ์ƒ์„ฑํ•˜์—ฌ ์ปฌ๋ ‰์…˜ ๋‚ด๋ถ€์˜ ํฌ์ธํ„ฐ๋“ค๋กœ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•˜์˜€๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ์ฝ”๋“œ๋Š” ๊ฐ์ฒด์˜ ๋™์ ์ƒ์„ฑ, ํ•ด์ œ์— ๊ด€๋ จ๋œ ๊ฒƒ๋“ค์„ ์ฒ˜๋ฆฌํ•  ์ฑ…์ž„์ด ์žˆ์—ˆ๋‹ค.

์ €์ˆ˜์ค€ ์ž๋ฃŒ๊ตฌ์กฐ์ธ ํฌ์ธํ„ฐ๋ฅผ ์ง์ ‘์ƒ์š”ํ•จ์œผ๋กœ์„œ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ์ 
* ํฌ์ธํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๊ฒƒ์€ ๊ทธ ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๊ฒƒ๊ณผ๋Š” ๋‹ค๋ฆ„.
* ํฌ์ธํ„ฐ์˜ ์†Œ๋ฉธ์ด ๊ทธ ๊ฐ์ฒด์˜ ์†Œ๋ฉธ์„ ์˜๋ฏธํ•˜์ง€ ์•Š๋Š”๋‹ค. (memory leak)
* ํฌ์ธํ„ฐ ์†Œ๋ฉธ์‹œํ‚ค์ง€ ์•Š๊ณ , ๊ฐ์ฒด๋ฅผ ์†Œ๋ฉธํ• ๊ฒฝ์šฐ dangling pointer ๋ฐœ์ƒ.
* ํฌ์ธํ„ฐ ์ƒ์„ฑ์‹œ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด, ํฌ์ธํ„ฐ๋ฅผ ๋ฐ”์ธ๋”ฉ๋˜์ง€ ์•Š์€ ์ƒํƒœ๊ฐ€๋œ๋‹ค.
๋งˆ์ง€๋ง‰ 2๊ฐ€์ง€์˜ ๊ฒฝ์šฐ๋Š” ๊ทธ ํฌ์ธํ„ฐ๋ฅผ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ฐธ์กฐํ•  ๊ฒฝ์šฐ ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.

13.5์˜ Student_info ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋‚ด๋ถ€์˜ Core๊ฐ์ฒด๋ฅผ ๋ณผ ์ˆ˜์—†๊ณ , ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๊ฐ€ ๋˜๋„๋ก์€ ํ–ˆ์œผ๋‚˜, ๋ฉ”์†Œ๋“œ๋“ค์ด Coreํด๋ž˜์Šค์˜ public์—ฐ์‚ฐ๋“ค์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ฅด๋Š” ๊ฒƒ๋“ค์ด ๋งŽ๋‹ค.
์ด์žฅ์—์„œ๋Š” ์ด๋Ÿฐ ํ•ธ๋“ค(handle)ํด๋ž˜์Šค๋ฅผ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋œ๋‹ค.

1.1.1. 14.1.1 ์ œ๋„ค๋ฆญ ํ•ธ๋“ค ํด๋ž˜์Šค(generic handle class)

์ด ํด๋ž˜์Šค๋Š” ๊ฐ์ฒด์˜ ํ˜•์— ๋ฌด๊ด€ํ•œ๊ฒŒ ๋™์ž‘ํ•˜์—ฌ์•ผ ํ•˜๋ฏ€๋กœ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ž‘์„ฑํ•œ๋‹ค.
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, ๊ณ„์ˆ˜๊ธฐ)๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ฐ์ฒด์˜ ์ƒ์„ฑ, ๋ณต์‚ฌ, ์†Œ๋ฉธ์‹œ ์ด ์นด์šดํ„ฐ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ๊ฐฑ์‹ ํ•œ๋‹ค.
~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 ํ•จ์ˆ˜ ํ˜ธ์ถœ์‹œ ๊ธฐ์กด์˜ ๋‚ด๋ถ€ ๋ฉค๋ฒ„๋ฅผ ์†Œ๋ฉธ์‹œํ‚ค๊ณ , ๋‹ค์‹œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ• ๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
~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๋ฅผ ํ†ตํ•ด์„œ ๋ณต์‚ฌ๋œ ๊ฒƒ์„ ๋ฆฌํ„ดํ•จ์œผ๋กœ์„œ ์›๋ณธ ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ์˜ ๋ณ€ํ˜•์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:22:24
Processing time 0.0104 sec