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.0639 sec