MoreEffectiveC++
1.1. Item 25: Virtualizing constructors and non-member functions ¶
- Item 25: ์์ฑ์์ ๋น๋ฉค๋ฒ ํจ์๋ฅผ ๊ฐ์์ผ๋ก ๋์๊ฐ๊ฒ ํ๊ธฐ.
1.1.1. Virtual Constructor : ๊ฐ์ ์์ฑ์ ¶
๊ฐ์ ์์ฑ์, ์ด๊ฒ์ ๊ดํด์ ์๊ฐํด ๋ณด๊ธฐ๋ ์ข ์์ํ๋ค. ์ฌ์ค ๊ฐ์ ํจ์๋ฅผ ๋ถ๋ฅผ๋ ค๋ฉด, ๊ฐ์ฒด์๋ํ ์ฐธ์กฐ๋, ํฌ์ธํฐ๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋๋ฐ, ์์ฑํ ๋ ๋ถํฐ ๊ฐ์(virtual) ํจ์๋ฅผ ์ฌ์ฉํ๋ค? ์ข ์ด์ํ์ง ์์๊ฐ? ์ด๋จ๋, ์ด๋ป๊ฒ ์ด ๊ฐ์ ์์ฑ์ ๋ผ๋๊ฑธ ์จ๋จน์์ ์์๊บผ?
์ฌ์ค ๊ฐ์ ์์ฑ์๋ผ๋๊ฑด ์กด์ฌํ์ง ์๋๋ค. ํ์ง๋ง ์ด๋ฅผ ๋น์ทํ๊ฒ ๊ตฌํํ๋ ๊ฒ์ด๋ค. ์๋ฅผ๋ค์๋ฉด ๋น์ ์ด newsletter์ ๋ณด๋ด๋ ์ดํ๋ฆฌ์ผ์ด์
์ ์ง๋๋ฐ, ์ฌ๊ธฐ์ ๊ธ๊ณผ ๊ทธ๋ฆผ ๋ฐ์ดํฐ ์ธ์๋ก ๊ตฌ์ฑ์ํจ๋ค๊ณ ๊ฐ์ ํ๋ฉด ์ด๋ ๊ฒ ๋ง๋ค์ ์์ ๊ฒ์ด๋ค.
์ด๋ฐ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ด ํํ๋๋ค.
~cpp
class NLComponent{ // News Letter ์ ๋ถ๋ชจ ์ธ์
public:
...
};
class TextBlock:public NLComponent{ // ๊ธ์ ํํํ๋ ์ธ์
public:
...
};
class Graphic:public NLComponent{ // ๊ทธ๋ฆผ์ ํํํ๋ ์ธ์
public:
...
};
class NewsLetter { // ๊ธ๊ณผ, ๊ทธ๋ฆผ์ ๊ฐ์ง๋ News Letter
public:
...
private:
list<NLComponent*> components; // ๊ธ๊ณผ ๊ทธ๋ฆผ ์ธ์์ ์ ์ฅ์
};
list ํด๋์ค๋ STL๋ก ์ด๋ฃจ์ด์ ธ ์๋๋ฐ, Item 35๋ฅผ ์ฐธ๊ณ ํ๋ฉด ์ ๋ณด๋ฅผ ์ป์์ ์๋ค. ๋จ์ํ ์ด์ค ์ฐ๊ฒฐ ๋ฆฌ์คํฌ(double linked list)๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฌด๋ฆฌ๊ฐ ์์ ๊ฒ์ด๋ค.
NewsLetter ๊ฐ์ฒด๋ ์๋ง ๋์คํฌ์์ ์๋ฃ๋ฅผ ์ ์ฌํ ๊ฒ์ด๋ค. NewsLetter๊ฐ ๋์คํฌ์์ ์๋ฃ๋ฅผ ๊ฐ์ง๊ณ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด istream์ ์ฌ์ฉํด์ NewsLetter๋ฅผ ๊ตฌ์ฑํ ๊ฐ์ฒด๋ค์ ์์ฑํ๋ค๊ณ ๊ฐ์ ํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ค์ ๋๊ฐ ๋ง๋ค์ ์๋๋ฐ
๊ฐ์ง ์ฝ๋๋ก ์ด ์์ฑ์๋ฅผ ๋๊ฐ ํํํ๋ฉด
ํน์ ์ฝ๊ฐ ์๋ฅผ ์จ์ readComponent๋ฅผ ํธ์ถํ๋ ์์ผ๋ก ๋ฐ๊พผ๋ค๋ฉด
readComponent๊ฐ ๋ฌด์์ ์ด๋ป๊ฒ ํ๋์ง ๊ถ๋ฆฌํด ๋ณด์. ์์ ์ธ๊ธํ๋ฏ์ด readComponent๋ ๋ฆฌ์คํธ์ ๋ฃ์ TextBlock๋ Graphicํ์ ๊ฐ์ฒด๋ฅผ ๋์คํฌ์์ ์ฝ์ด ๋๋ฆฐ ์๋ฃ๋ฅผ ๋ฐํ์ผ๋ก ๋ง๋ค์ด ๋ธ๋ค. ๊ทธ๋ฆฌ๊ณ ์ต์ข
์ ์ผ๋ก ๋ง๋ค์ด์ง ํด๋น ๊ฐ์ฒด์ ํฌ์ธํฐ๋ฅผ ๋ฐํํด์ list์ ์ธ์๋ฅผ ๊ตฌ์ฑํ๊ฒ ํด์ผ ํ ๊ฒ์ด๋ค. ์ด๋ ๋ง์ง๋ง ์ฝ๋์์ ๊ฐ์ ์์ฑ์์ ๊ฐ๋
์ด ๋ง๋ค์ด ์ ธ์ผ ํ ๊ฒ์ด๋ค. ์
๋ ฅ๋ ๋์๋ฃ์ ๊ธฐ์ด๋์ด์, ์์์ ๋ง๋ค์ด ์ธ์. ๊ฐ๋
์์ผ๋ก๋ ์ณ์ง๋ง ์ค์ ๋ก๋ ๊ทธ๋ ๊ฒ ๊ตฌํ๋ ์๋ ์์ ๊ฒ์ด๋ค. ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ๋ถํฐ ํ์ ์๊ณ ์์ด์ผ ํ๋๊ฑด ์๋ช
ํ๋๊น. ๊ทธ๋ ๋ค๋ฉด ๋น์ทํ๊ฒ ๊ตฌํํด ๋ณธ๋ค?
~cpp
class NewsLetter {
public:
NewsLetter(istream& str);
...
};
~cpp
NewsLetter::NewsLetter(istream& str)
{
while(str){
๋ค์์ ์ถ๊ฐ๋ ์ธ์ ๊ฐ์ฒด(component object)๋ฅผ str๋ก ๋ถํฐ ์ฝ๋๋ค.
newsletter์ ์ธ์์ค ๋ฆฌ์คํธ์ธ components์ ๋ง๋ ๊ฐ์ฒด๋ฅผ ๋ฃ๋๋ค.
}
}
~cpp
class NewsLetter{
publicc:
...
private:
// ์์ํ ๋์คํฌ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด ๋๋ฆฌ๋ istream๊ณผ ์๋ฃ str์์
// ํด๋น ์๋ฃ๋ฅผ ํด์ํ๊ณ , ์๋ง๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ๋ฐํธ๋ํ๋ readComponent๊ฐ์ฒด
static NLComponent * readComponent(istream& str);
};
NewsLetter::NewsLetter(istream& str)
{
while (str) {
// readComponent๊ฐ ํด์ํ ๊ฐ์ฒด๋ฅผ newsletter์ ๋ฆฌ์คํธ ๋ง์ง๋ง์ ์ถ๊ฐ์ํค๋ ๊ณผ์
components.push_back(readComponent(str));
}
}
๊ฐ์ ์์ฑ์์ ๋ฐฉ์์ ํ ์ข
๋ฅ๋ก ํน๋ณํ๊ฒ ๊ฐ์ ๋ณต์ ์์ฑ์(virtual copy constructor)๋ ๋๋ฆฌ ์ฐ์ธ๋ค. ์ด ๊ฐ์ ๋ณต์ฌ ์์ฑ์๋ ์๋ก์ด ์ฌ๋ณธ์ ํฌ์ธํฐ๋ฅผ ๋ฐํํ๋๋ฐ copySlef๋ cloneSelf๊ฐ์ ๋ณต์ฌ์ ๊ฐ๋
์ผ๋ก ์์ฑ์๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด๋ค. ๋ค์ ์ฝ๋์์๋ clone์ ์ด๋ฆ์ ์ฐ์๋ค.
๋ณด๋ค์ํผ ํด๋์ค์ ๊ฐ์ ๋ณต์ฌ ์์ฑ์๋ ์ค์ ๋ณต์ฌ ์์ฑ์๋ฅผ ํธ์ถํ๋ค. ๊ทธ๋ฌ๋ฏ๋ก "๋ณต์ฌ" ์๋ฏธ๋ก๋ ์ผ๋ฐ ๋ณต์ฌ ์์ฑ์์ ์ํ ๊ธฐ๋ฅ์ด ๊ฐ๋ค ํ์ง๋ง ๋ค๋ฅธ ์ ์ ๋ง๋ค์ด์ง ๊ฐ์ฒด๋ง๋ค ์ ๊ฐ๊ฐ์ ์๋ง๋ ๋ณต์ฌ ์์ฑ์๋ฅผ ๋ง๋ ๋ค๋ ์ ์ด ๋ค๋ฅด๋ค. ์ด๋ฐ clone์ด NewsLetter ๋ณต์ฌ ์์ฑ์๋ฅผ ๋ง๋ค๋ NLComponent๋ค์ ๋ณต์ฌํ๋๋ฐ ๊ธฐ์ฌ๋ฅผ ํ๋ค. ์ด๋ป๊ฒ ๋ ์ฌ์ด ์์
์ด ๋๋์ง ๋ค์ ์์ ๋ฅผ ๋ณด๋ฉด ์ดํด ํ ์ ์์ ๊ฒ์ด๋ค.
STL์ด ์์ํ๋ค๋ฉด ๋์ค์ ์ตํ๋ผ ํ์ง๋ง ์์ ์์ด๋์ด๋ ์ฃผ์๋ฌธ์ผ๋ก ์ธํด ์ดํด๊ฐ ๊ฐ๊ฒ์ด๋ค. ๊ฐ์ ๋ณต์ฌ ์์ฑ์๋ก ์ธํด์, ๊ฐ์ฒด ๋ณต์ฌ๊ฐ ์๋นํ ๊ฐํธํด ์ง๋ค.
~cpp
class NLComponent{
public:
// ๊ฐ์ ๋ณต์ฌ ์์ฑ์ virtual copy constructor ์ ์ธ
virtual NLComponent * clone() const = 0;
...
};
class TextBlock: public NLComponent{
public:
virtual TextBlock * clone() const // ๊ฐ์ ๋ณต์ฌ ์์ฑ์ ์ ์ธ
{ return new TextBlock(*this); }
...
};
class Graphic:public NLComponent{
public:
virtual Graphic * clone() const // ๊ฐ์ ๋ณต์ฌ ์์ฑ์ ์ ์ธ
{ return new Graphic(*this); }
...
};
~cpp
class NewsLetter{
public:
NewsLetter(const NewsLetter* rhs); // NewsLetter์ ๋ณต์ฌ ์์ฑ์
...
private:
list<NLComponent *> components;
};
NewsLetter::NewsLetter(const NewsLetter* rhs)
{
for (list<NLComponent*>::constiterator it = rhs.components.begin();
it != rhs.components.end();
++it){
// it์ rhs.components์ ํ์ฌ๋ฅผ ๊ฐ๋ฆฌํค๋ ์ธ์๋ก, ๋ณต์ฌ๋์ด์ผ ํ ๊ฐ์ฒด์ด๋ค.
// ํ์ ๊ฐ๋ฆฌ๋ ์์
์์ด ๊ทธ๋ฅ clone์ ์ด์ฉํด ๊ณ์ ๋ณต์ฌํด ๋ฒ๋ฆฌ๋ฉด ๊ฐ ํ์ ์๋ง๋ ๋ณต์ฌ
// ์์ฑ์๊ฐ ๋ถ๋ฆฌ๋ฉด์ ๋ณต์ฌ ๋๋ ๊ฒ์ด๋ค.
components.push_back((it*)->clone());
}
}
1.1.2. Making Non-Member Functions Act Virtual : ๋น๋ฉค๋ฒ ํจ์๋ฅผ ๊ฐ์ ํจ์์ฒ๋ผ ๋์ํ๊ฒ ํ๊ธฐ ¶
์์ฑ์๋ ์ค์ ๋ก ๊ฐ์ ํจ์๊ฐ ๋ ์ ์๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ๋น๋ฉค๋ฒ ํจ์๋ค ์ญ์ ๋ง์ฐฌ๊ฐ์ง ์ด๋ฆฌ๋ผ, ํ์ง๋ง ๊ทธ๋ฌํ ๊ธฐ๋ฅ์ด ํ์ํ ๋๊ฐ ์๋ค. ๋ฐ๋ก ์ ์์ ์์ NLComponent์ ๊ทธ๊ฒ์์ ์ ๋๋ ํด๋์ค๋ค์ ์๋ฅผ ๋ค์ด ๋ณด์๋ฉด ์ด๋ค์ operator<<์ผ๋ก ์ถ๋ ฅ์ ํ์๋ก ํ ๋ ์ด๋ฆฌ๋ผ. ๋ญ ๋ค์๊ณผ ๊ฐ์ด ํ๋ฉด ๋ฌธ์ ์๋ค.
ํ์ง๋ง ์ถ๋ ฅํด์ผํ ์คํธ๋ฆผ ๊ฐ์ฒด๊ฐ righ-hand ๊ฐ์ฒด๋ผ๋๊ฒ์ด ์ฌ์ฉ์ ์
์ฅ์์ ๋ถํธํ๊ฒ ๋ง๋ ๋ค. ์ฐ๋ฆฌ๊ฐ ๋ณดํต ์ฌ์ฉํ๋ ๊ฒ์ฒ๋ผ ์คํธ๋ฆผ ๊ฐ์ฒด์ ์ถ๋ ฅํ ๊ฐ์ฒด๋ฅผ ๋ฃ๋ ๋ค๋ ๊ฐ๋
์ด ์ ์ฉ๋์ง ์๋ ๊ฒ์ด๋ฆฌ๋ผ. ํ์ง๋ง, ์ ์ญ ํจ์๋ friendํจ์๋ฅผ ์ด์ฉํด์ ๊ตฌํํ๋ค๋ฉด ๋์ด์ ๊ฐ์ํจ์๋ก ๊ตฌํํ ์๊ฐ ์๊ฒ ๋๋ค. ์ฌ๊ธฐ์์ ๋ฐฉ๋ฒ์ด ๋น๋ฉค๋ฒ ํจ์๋ฅผ ์ด์ฉํ๋ ๊ฒ์ด๋ค.
~cpp
class NLComponent{
public:
// operator<<์ ๊ฐ์ ํจ์
virtual ostream& operator<<(ostream& str) const = 0;
...
};
class TextBlock:public NLComponent{
public:
virtual ostream& operator<<(ostream& str) const;
};
class Graphic:public NLComponent{
public:
virtual ostream& operator<<(ostream& str) const;
};
TextBlock t;
Graphic g;
...
t << cout;
g << cout;
๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ ํจ์๋ก ์ถ๋ ฅ์ ๊ตฌํํ๊ณ , ์ ์ญ์ด๋ , namespace๋ก ๋ฌถ์ฌ ์๋ , ๋น ๋ฉค๋ฒ ํจ์๋ก ์คํธ๋ฆผ ๊ฐ์ฒด์์ ์ถ๋ ฅ์ ๊ณ ๋ฆฌ๋ฅผ ์ฐ๊ฒฐ์์ผ์, ๋น๋ฉค๋ฒ ํจ์๊ฐ ๊ฐ์ํจ์์ฒ๋ผ ๋์๊ฐ๋๋ก ๊ตฌํํ๋ค.
๊ฐ์ ํจ์์ ์ญํ ์ ๋น๋ฉค๋ฒ(non-member)ํจ์๋ก ๊ตฌํํ ์ฌ๋ก์ด๋ค. ๋น ๋ฉค๋ฒ ํจ์์ด์ง๋ง inline์ ํตํด์ ๊ฐ์ ํจ์์์ ์ง์ ์ฐ๊ฒฐ ํต๋ก๋ฅผ ๋ง๋ค์๋ค.
~cpp
class NLComponent {
public:
virtual ostream& print(ostream& s) const = 0;
...
};
class TextBlock: public NLComponent {
public:
virtual ostream& print(ostream& s) const;
...
};
class Graphic: public NLComponent {
public:
virtual ostream& print(ostream& s) const;
...
};
inline
ostream& operator<<(ostream& s, const NLComponent& c)
{
return c.print(s);
}
๋น๋ฉค๋ฒ ํจ์์ ๊ฐ์(virtual)๊ด๋ จ ์ฌ์ฉ์ ๋ํ์ฌ ๋ ๋ค๋ฃจ์๋ฉด ๋ด์ฉ์ด ๋ณต์กํด ์ง๋ค. ์ด์ ๋ํ ๊ด๋ จ ์ฌํญ์ Item 31์ ์ฐธ๊ณ ํ๋ผ
1.2. Item 26: Limiting the number of objects of a class ¶
- Item 26: ๊ฐ์ฒด ์ซ์ ์ ํํ๊ธฐ.
- ์์ฑ์์ฃผ : ์ด ๋ถ๋ถ์ Singleton ํจํด๊ณผ ์ฐ๊ดํด์ ์๊ฐํ๋ฉด ์ฌ๋ฏธ์์ ๊ฒ ๊ฐ๋ค. Singleton ํจํด์ด DP์ ๋
ผ์๋ ๋ ์ด๊ฒ์ ๊ฐ์ ์ํ๊ฒ์ด ์์ฝ๋ค. 1995๋
์ ๋ฐ๊ฐ์ด๋ผ STL๋ ์ ๋๋ก ๋ค๋ฃจ์ง ์์๊ณ , C++์ ๊ธฐ๋ณธ์ ์ธ ๋ฌธ๋ฒ์ ์ด์ฉํด ๊ตฌํํ์๋ค. MEC++๋ Techniques ๋ถ๋ถ์ C++์ ๋ฌธ๋ฒ๊ณผ ๊ฐ๋
์ ๊ทนํ์ผ๋ก ์ด๋ค๋ ๋๋์ด ๋ ๋ค.
1.2.1. Allowing Zero or One Objects : 0 ํน์ ํ๋์ ๊ฐ์ฒด ๋ง์ ํ์ฉํ๋ ๋ฐฉ๋ฒ ¶
๊ฐ์ฒด๋ค์ด ์์ฑ๋ ๋ ๊ผญ ํ๋ ์ผ์ด ์๋ค. ๋ฐ๋ก ์์ฑ์๋ฅผ ๋ถ๋ฅด๋ ์ผ์ด๋ค. ํ์ง๋ง ์ด๊ฑธ ๋ง์์ ์๋ ๋ฐฉ๋ฒ์ด ์์๊น? ๊ฐ์ ์ฅ์ด ๋ฐฉ๋ฒ์ ์์ฑ์๋ฅผ private(์ฌ์ญ)์ธ์๋ก ๋ฌถ์ด ๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค. ๋ค์์ ๋ณด์
์ ์ด๋ ๊ฒ ํ๋ฉด ์์ฑ์๊ฐ private์ํ๋ผ์ ์ธ๋ถ์์ ์์ฑ์๋ฅผ ๋ถ๋ฅผ์ ์๊ธฐ ๋๋ฌธ์, ์ธ๋ถ์์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค. ์ด๋ฐ ์์ด๋์ด๋ฅผ ๋ฐํ์ผ๋ก ์์ฑ ์์ฒด์ ์ ํ์ ๊ฐํด ๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค. ๊ทธ๋ผ ์ฒ์์ ๋งํ ํ๋ฆฐํฐ์ ์์ ๋ฅผ ์์ ์์ด๋์ด๋ฅผ ๊ตฌํํด ๋ณด์.
ํด๋น ๋์์ธ์ ์ธ๊ฐ์ง์ ์ค์ ์ผ๋ก ์ดํด ํ๋ฉด ๋๋ค. ์ฒซ๋ฒ์งธ Printerํด๋์ค์ ์์ฑ์๋ฅผ private(์ฌ์ญ)์ธ์๋ก ์ค์ ํ๋ค. ์ด๋ ๊ฐ์ฒด ์์ฑ์ ์ ํํ๋ค. ๋๋ฒ์งธ ์ ์ญ ํจ์์ธ thePrinter๋ฅผ Printerํด๋์ค์ friend๋ก ์ ์ธํ๋ค. ๊ทธ๋์ ์ด thePrinter๊ฐ ์ฒซ๋ฒ์งธ์์์ ์ ํ์ ์๊ด์์ด ๊ด์ฌ ๊ฐ๋ฅํ๋๋ก ๋ง๋ ๋ค. ๋ง์ง๋ง์ผ๋ก(์ธ๋ฒ์งธ) ์ ์ญํจ์์ธ thePrinter ๋ด๋ถ์ ์ ์ (static) Printer ๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค. ์ด๋ ์ค์ง ํ๋๋ง์ ๊ฐ์ฒด๋ฅผ thePrinter๋ด๋ถ์ ์ ์ง์ํจ๋ค.
~cpp
class CantBeInstantiated {
private:
CantBeInstantiated();
CantBeInstantiated(const CantBeInstantiated&);
...
};
~cpp
class PrintJob; // ๋ฏธ๋ฆฌ ์ ์ธ, ํ๋ฆฐํฐ ์์
์ ์ฐ์ด๋ ๊ฐ์ฒด. ์ฐธ๊ณ Effective C++ Item 34
class Printer {
public:
void submitJob(const PrintJob& job);
void reset();
void performSelfTest();
...
friend Printer& thePrinter(); // ์ด friend ํจ์๊ฐ ์ ์ผํ ๊ฐ์ฒด ํ๋๋ฅผ ์ ์ง ์ํค๊ณ
// ๊ฐ์ฒด์ ์ฌ์ฉ๊ถํ์ ๋ถ์ฌ ํ๋ ์ญํ ์ ํ๋ค.
private:
Printer();
Printer(const Printer& rhs);
...
};
Printer& thePrinter()
{
static Printer p; // ๋จ์ผ์ Printer ๊ฐ์ฒด(the single printer object)
return p;
}
ํด๋ผ์ด์ธํธ ์
์ฅ์์๋ ์ด๋ ๊ฒ ์ฌ์ฉํ๋ฉด ๋๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ ๊ตฌํ์์๋ thePrinter๊ฐ "์ ์ญ ๊ณต๊ฐ์ ์ฌ์ฉํด์ผ ํ๋ค." ๊ฒ์ผ๋ก ์ฝ๋๋ฅผ ์ฝํ๊ฒ ๋ง๋ ๋ค. ์๋ค ์ํผ, ์ ์ญ ๊ณต๊ฐ์ ์ฌ์ฉ์ ๋๋๋ก์ด๋ฉด ํผํด์ผ ํ๋ ๋ฐฉ๋ฒ์ด๋ฉฐ, thePrinter๋ฅผ Printerํด๋์ค ๋ด๋ถ์ ์จ๊ธฐ๊ธฐ๋ฅผ ์ถ์ฒํ๋ค. thePrinter๋ฅผ Printerํด๋์ค ๋ด๋ถ ๋ฉ์๋๋ก ๋ฃ์ด ๋ฒ๋ฆฌ๊ณ , friend๋ฅผ ์ญ์ ํด ๋ณด์.
๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ ์ธก์์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ์ฌ์ฉํ๋ฉด ๋๊ฒ ๋ค.
์ ์ญ ๊ณต๊ฐ ์ฌ์ฉ์ ๋ํ ๋ฌธ์ ์ ํด๊ฒฐ์ฑ
์ ๋๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ํ๋ค๋ฉด, name space๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. ๋ค์๊ณผ ๊ฐ์ด ๋จ์ํ PrintingStuff name space๋ก ๋ฌถ์ด ๋ฒ๋ฆฐ๋ค.
๊ทธ๋ฆฌ๊ณ thePrinter๋ฅผ ํธ์ถํ๋ ค๋ฉด ์ด์ ๋ ์ด๋ ๊ฒ ํด์ผ ํ๋ค.
๋ฌผ๋ก using ํค์๋๋ฅผ ์ฌ์ฉํด์ ํด๋น ์ด๋ฆ์ ์์ ๋กญ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
thePrinter ๋ฅผ ์ ์ฉํ ๋ ๋๊ฐ์ง ์๊ฐํด์ผํ ๋ฏธ๋ฌํ ๋ฌธ์ ์ ์ด ์๋ค.
~cpp
class PrintJob {
public:
PrintJob(const string& whatToPrint);
...
};
string buffer;
... // ๋ฒํผ์ ์ธ์๋ฅผ ๋ฃ๋ ์ฝ๋
thePrinter().reset();
thePrinter().submitJob(buffer); // ์์ ์ฐธ์กฐ(const reference)๋ผ์,
// ์์ ๊ฐ์ฒด๊ฐ ์์ฑ๋์ด ์คํ๋๋ค.
~cpp
class Printer {
public:
static Printer& thePrinter(); // ์ธ๋ถ์์ ํธ์ถ ๊ฐ๋ฅํ๋๋ก static์ผ๋ก ์ ์ธํ๊ณ
...
private:
Printer();
Printer(const Printer& rhs);
...
};
Printer& Printer::thePrinter() // friend๋ง ์์ด์ง ๋ง์ฐฌ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ์ํ๋ค.
{
static Printer p;
return p;
}
~cpp Printer::thePrinter().reset(); Printer::thePrinter().submitJob(buffer);
~cpp
namespace PrintingStuff { // namespace์ ์์
class Printer { // namespace๋ก์ ์ด ํด๋์ค๋
public: // PrintingStuff namespace ์์ ์กด์ฌํ๋ ๊ฒ์ด๋ค.
void submitJob(const PrintJob& job);
void reset();
void performSelfTest();
...
friend Printer& thePrinter();
private:
Printer();
Printer(const Printer& rhs);
...
};
Printer& thePrinter() // ์ด friend ํจ์ ์ญ์ ์ ์ญ์ด ์๋
{ // PrintingStuff namespace์์ ์กด์ฌ ํ๋ ๊ฒ์ด๋ค.
static Printer p;
return p;
}
} // namespace์ ๋
~cpp PrintingStuff::thePrinter().reset(); PrintingStuff::thePrinter().submitJob(buffer);
~cpp
using PrintingStuff::thePrinter; // thePrinter๋ฅผ ํ์ฌ์ namespace์์์
// ์์ ๋ก์ด ์ธ์ ์๊ฒ ๋ง๋ ๋ค.
thePrinter().reset(); // ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉํ๋ ๊ณผ์
thePrinter().submitJob(buffer);
์ฒซ๋ฒ์งธ๋ก ๋ง๋ค์ด์ง๋ ๊ฐ์ฒด์ ์์น์ด๋ค. ์์ ์ ์๋ ๋๊ฐ์ง์ ๋ฐฉ๋ฒ์์, Printer ์ ์ (staitc) ๊ฐ์ฒด๊ฐ ํ๋๋ friend๋ก ํด๋์ค์ ์ ์ด๊ถ์ ํ๋ํ ํจ์ ๋ด๋ถ์ ์๊ณ , ๋ ํ๋๋ ํด๋์ค ๋ฉค๋ฒ ๋ฉ์๋ ๋ด๋ถ์ ์๋ค. ํจ์์ ์๋ ๊ฒฝ์ฐ์๋ ์ ์ (static) ๊ฐ์ฒด๋ ํญ์ ๋ง๋ค์ด์ ธ ์๋ค. ์ด ์๋ฏธ๋ ํด๋น ์ฝ๋์ ํ๋ก๊ทธ๋จ์ด ์์๋ ๋ ๋ถํฐ ์์ ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด ์ง๋ค๋ ์๋ฏธ์ด๋ค. ์ฆ, ํ๋ฒ๋ ๊ทธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ง ์์๋, ๊ฐ์ฒด๋ ์ด๋ฏธ ๋ง๋ค์ด์ ธ ๋น์ฉ์ ์ง์ถํ๊ฒ ํ๋ค. ๋ฐ๋ฉด์, ํจ์ ๋ฉค๋ฒ ๋ฉ์๋ ๋ด๋ถ์ ์ ์ (static)๊ฐ์ฒด๋ฅผ ๋ง๋ค ํ์์ ๊ฒฝ์ฐ์๋ ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ์ญํ ์ ํ๋ ๋ฉ์๋์ธ Printer::thePrinter ๊ฐ ์ ์ผ ์ฒ์ ํธ์ถ๋ ๋ ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ค. ์ด๊ฒ์ C++์์ "์ฌ์ฉํ์ง ์๋ ๊ฐ์ฒด์ ๋ํ ๋น์ฉ์ ์ง๋ถํ์ง ์๋๋ค."์ ์ค๊ณ ๋ค์ ๋ณต์กํ ์ด๋
์ ๊ทผ๊ฐ์ ๋ ๊ฐ๋
์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ๋ณต์กํ ๊ฐ๋
์ ๋น์ ์ ํด๊น๋ฆฌ๊ฒ ๋ง๋ ๋ค.
( DeleteMe Translation unit์ ํด์์ด ๋ถ๋ถ๋ช
ํ๋ค.)
๋ ์ด ๋์ ๋ค๋ฅธ ์ทจ์ฝ์ ์ ์ด๊ธฐํ ๋๋ ์๊ฐ์ด๋ค. ์ฐ๋ฆฌ๋ ํจ์์ ๊ฒฝ์ฐ์ ์ด๊ธฐํ ์๊ฐ์ ์ ํํ ์์ ์๋ค. ์์ ์ฒ์ ์ด๋๊น ํ์ง๋ง ๋ฉค๋ฒ ๋ฉ์๋๋ก ๊ตฌํ์์๋ ๋ชจํธํ๋ค. C++๋ ํ์คํ ํน๋ณํ๊ฒ ํด์ํด์ผ ํ ๋ถ๋ถ(๋จ์ผ ๊ฐ์ฒด์์ ์์ค ์ฝ๋ ๋ชธ์ฒด ๋ถ๋ถ ๋ฐ์)์ ์ ์ ์ธ์๋ค์ ๋ํ ์ด๊ธฐํ ์์๊ฐ ๋ณด์ฅ ๋๋ค. ํ์ง๋ง ์๋ก ๋ค๋ฅธ ํด์ ๋ถ๋ถ(translation unit)์ ์๋ ์ ์ ๊ฐ์ฒด๋ค์ ์ด๊ธฐํ ์์์ ๋ํด์๋ ๋งํ ์๊ฐ ์๋ค. ์ด๊ฒ์ ๋จธ๋ฆฌ๋ฅผ ์ํ๊ฒ๋ง ํ ๋ฟ์ด๋ค.
๋ ์ด ๋์ ๋ค๋ฅธ ์ทจ์ฝ์ ์ ์ด๊ธฐํ ๋๋ ์๊ฐ์ด๋ค. ์ฐ๋ฆฌ๋ ํจ์์ ๊ฒฝ์ฐ์ ์ด๊ธฐํ ์๊ฐ์ ์ ํํ ์์ ์๋ค. ์์ ์ฒ์ ์ด๋๊น ํ์ง๋ง ๋ฉค๋ฒ ๋ฉ์๋๋ก ๊ตฌํ์์๋ ๋ชจํธํ๋ค. C++๋ ํ์คํ ํน๋ณํ๊ฒ ํด์ํด์ผ ํ ๋ถ๋ถ(๋จ์ผ ๊ฐ์ฒด์์ ์์ค ์ฝ๋ ๋ชธ์ฒด ๋ถ๋ถ ๋ฐ์)์ ์ ์ ์ธ์๋ค์ ๋ํ ์ด๊ธฐํ ์์๊ฐ ๋ณด์ฅ ๋๋ค. ํ์ง๋ง ์๋ก ๋ค๋ฅธ ํด์ ๋ถ๋ถ(translation unit)์ ์๋ ์ ์ ๊ฐ์ฒด๋ค์ ์ด๊ธฐํ ์์์ ๋ํด์๋ ๋งํ ์๊ฐ ์๋ค. ์ด๊ฒ์ ๋จธ๋ฆฌ๋ฅผ ์ํ๊ฒ๋ง ํ ๋ฟ์ด๋ค.
๋๋ฒ์งธ๋ก ๋ฏธ๋ฌํ ๋ฌธ์ ๋ผ๋ฉด, inline๊ณผ ์ ์ ๊ฐ์ฒด์ ๊ด๊ฒ์ด๋ค. ๋ค์๊ณผ ๊ฐ์ ๋น๋ฉค๋ฒ ๋ฒ์ ์ thePrinter๋ฅผ ๋ณด๋ฉด
๋ค์๊ณผ ๊ฐ์ ์ฝ๋์ ํจ์๋ ๋งค์ฐ ์งง๋ค. ์ด๋ฐ ์งง์ ํจ์๋ ํจ์๋ณด๋ค inline ์์ผ์ ์๋๋ฅผ ๋์ด๋ ๊ฒ์ด ๋ ํจ๊ณผ์ ์ด๋ค. ํ์ง๋ง ๊ทธ๋ด์๊ฐ ์๋ค. ์ ๊ทธ๋ฐ๊ฐ ํ๋ฉด, inline์ ์๋ฏธ๋ ์ ํํ ํด๋น ํจ์๊ฐ ์ฐ์ด๋ ์ฝ๋๋ฅผ ํ์ฌ ํจ์์ ๋ชธ์ฒด๋ก ๊ต์ฒดํด ๋ฒ๋ฆฌ๋ ์ญํ ์ด๋ค. ๊ทธ๋ฐ๊ฒ ์ด๋ ๊ฒ ํ ๊ฒฝ์ฐ, ์์ ๊ฐ์ ํจ์๋ static๊ฐ์ฒด์ ์ฒ๋ฆฌ์์ ์๋ฌธ์ด ์๊ธด๋ค. ํด๋น ํจ์๊ฐ ํธ์ถ๋ ๊ณณ์ ์์ ๊ฐ์ ํจ์ ๋ชธ์ฒด๋ก ๊ต์ฒดํ๋ฉด, ๊ฐ ๊ต์ฒด ๋ถ๋ถ์ ์ ๋ถ ๋
๋ฆฝ์ ์ธ static ์ธ์๋ฅผ ๋ถ์ฌ ๋ฐ๋ ์
์ด ๋์ด ๋ฒ๋ฆฐ๋ค. ๊ทธ๋์ ์ ์ ์ธ์๋ฅผ ์ด ํจ์๋ inline์ ์ํค์ง ๋ชปํ๋ฉฐ, ์ด๋ฐ ์ ์ ์ธ์์ ์ฌ์ฉ์ ๋ฐ๋ผ ์ผ์ด๋๋ ์๋ฌธ์ internal linkage๋ฅผ ๊ฐ์ง ๋ฌธ์ ๋ผ๊ณ ํ๋ค. DeleteMe) ๋ ๋ฆผ ์์ฝ ์์ ํ์
~cpp
Printer& thePrinter()
{
static Printer p;
return p;
}
์, ๋๋ํ ์ฌ๋ ์ด๋ผ๋ฉด ๋น์ฐํ, ์ง๊ธ๊น์ง์ ์ฝ๋์์ ์๋ฌธ์ ๊ณผ ๋ฌธ๋ฒ์ ๋ํ ์์ํจ์ ์ผ์ผ ํฌ์ ์๋ค. thePrinter๋ ๋๋ค ๋ด๋ถ์ ์๋ static ๊ฐ์ฒด์ ์ฐธ์กฐ๋ฅผ ๋ฐํํ๋๋ฐ, ์ด "static ๊ฐ์ฒด๋ ํด๋น ํจ์,๋ฉ์๋์ ์์ญ(scop) ๋ด๋ถ์์ ์ฐ์ฌ์ผ์ง ์ธ๋ถ์์ ์ฐ์ด๋ฉด ์๋์ง ์๋๊ฐ?" ๋ผ๋ ์๋ฌธ์ด ๊ทธ๊ฒ์ด๋ค. ์ฆ, ํด๋ผ์ด์ธํธ ์
์ฅ์์ ์ด๋ค ๊ฐ์ฒด๋ ์จ๊ฒจ์ ธ(hidden)์๋ ์กด์ฌ์ด๊ณ , ์ด๊ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ ์๋ชป๋ ๋ฐฉ๋ฒ์ด๋ค. ๋ผ๊ณ ๋งํ ์ ์๊ฒ ๋๋ฐ, ๊ทธ๋์ ์๋ง ๋น์ ์ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ฒด์ ์ซ์๋ฅผ ์ธ๊ณ , ์ ํ๋ ๊ฐ์ฒด์ ์๋ณด๋ค ๋ ๋ง์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉ์ ์์ธ๋ฅผ ๋ฐ์์์ผ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ด ๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ผ ๋งํ ๊ฒ์ด๋ค.
์ด๋ฐ ์์ด๋์ด๋ numObject๋ฅผ ์ฌ์ฉํด์ Printer๊ฐ์ฒด์ ์๋ฅผ ์ ํ ์์ผ ๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค. ์์๋ ์ธ๊ธํ์๋ฏ์ด ๊ฐ์ฒด์ ์๊ฐ 1๊ฐ๋ฅผ ์ด๊ณผํ๋ฉด, TooManyObject ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค.
์ด๋ฌํ ์ ๊ทผ ๋ฐฉ๋ฒ์ ๋งค๋ ฅ์ ์ด๋ฉฐ, ๋จ์ง ๊ฐ์ฒด์ ์๋ฅผ 1๊ฐ์ ๊ตญํ ํ์ง ์๊ณ , ํน์ ์ซ์๋ก ์กฐ์ ํ ์ ์๋ ์ด์ ์ด ์๋ค. ์ฌ์ฉํ๊ธฐ๋ ๊ท์ฐฎ์๋ ๋ง์ด๋ค. ํ์ง๋ง ์ด ๊ฒ์ ๋ฌธ์ ๋ฅผ ๋ฐ๋ก ๋ค๋ฃจ์ด ์ฃผ๊ฒ ๋ค.
~cpp
class Printer {
public:
class TooManyObjects{}; // ๋๋ฌด ๋ง์ ๊ฐ์ฒด๋ฅผ ์๊ตฌํ๋ฉด
// ์ด ์์ธ๋ฅผ ๋ฐ์ ์ํจ๋ค.
Printer();
~Printer();
...
private:
static size_t numObjects;
Printer(const Printer& rhs); // ํ๋ฆฐํฐ๋ 1๊ฐ๋ง ํ์ฉํ๋ฉฐ, ์ฌ๋ณธ๋ ํ์ฉ ํ์ง
// ์๋๋ค. Item E27
};
~cpp
size_t Printer::numObjects = 0;
Printer::Printer()
{
if (numObjects >= 1) {
throw TooManyObjects();
}
๋ณดํต์ ์์ฑ ๊ณผ์ ์ ์ํํ๋ค.
++numObjects;
}
Printer::~Printer()
{
๋ณดํต์ ํ๊ดด ๊ณผ์ ์ ์ํํ๋ค.
--numObjects;
}
1.2.2. Context for Object Construction : ๊ฐ์ฒด์ ์์ฑ์ ์ํ ๊ตฌ๋ฌธ(๊ด๊ณ, ๋ฌธ๋งฅ, ์ํฉ) ¶
๋ฐฉ๊ธ ์์์ ์์ ๋ก ์ ์ํ ๋ฐฉ๋ฒ ์ญ์ ๋ฌธ์ ๋ ๋ดํฌํ๊ณ ์๋ค. ๊ฐ๋ น ํน๋ณํ ํ๋ฆฐํฐ์ธ ์ปฌ๋ฌ ํ๋ฆฐํฐ์ ๋ํ ํด๋์ค๋ฅผ ์์ฑํ๋ค๊ณ ๊ฐ์ ํด ๋ณธ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ค๊ณ ๊ฐ์ ํด ๋ณด์.
์ฒซ๋ฒ์งธ ๊ฐ์ฒด p๋ ์์กฐ๋กํ ์์ฑ๋๋ค. ํ์ง๋ง ์์ฐํ ๋ค๋ฅธ ํ๋ฆฐํฐ๋ฅผ ๋์์ผ๋ก ํ๊ณ ์๋ cp๋ ์์ฑ๋์ง ์๊ณ , TooManyObjects ์์ธ๋ฅผ ๋ฐ์ ์ํจ๋ค. ์ ๊ทธ๋ฌ๋์ง ๋ชจ๋๋ค ์์ ํ ๊ฒ์ด๋ค. ๋๋ถ์ด ๋น์ท ๋ ๋ค๋ฅธ ๊ฒฝ์ฐ๋ฅผ ์๊ฐ ํด ๋ณธ๋ค๋ฉด.
Printer ๊ฐ์ฒด๊ฐ ์กด์ฌํ ์ ์๋ ์ธ๊ฐ์ง์ ์ํฉ์์ ์ด๋ฐ ๋ฌธ์ ๋ ๋ฐ์ ๋ ์ ์๋ค. : ๊ทธ๋ฅ ๊ทธ๋ค ์์ฒด๋ฅผ ์ ์ธํด์ ์ฌ์ฉํ๊ธฐ. ๋ค๋ฅธ ํด๋์ค๋ก ์ ๋๋ ๋. ์ข๋ ํฐ ํด๋์ค์์ ํด๋น ํด๋์ค๋ฅผ ์ธ์๋ก ํฌ์ฉํ ๋ ์ด๋ค. ํ์ง๋ง ์ซ์๋ก ์ ์ดํ๊ณ , ์์ธ๋ฅผ ๋ฐ์์ํค๋ ๋ฐฉ๋ฒ์ด ์๋ ์์ฑ์๊ฐ ์ฌ์ญ(private)์ธ์๋ก ๋ค์ด๊ฐ ๊ฒฝ์ฐ์๋ ํด๋น ํด๋์ค์์ ์ ๋๋ ํด๋์ค๋ค๋ ์์ฑํ์ง ๋ชปํ๋ฉฐ, ๋ค๋ฅธ ํด๋์ค์ ์ธ์๋ก๋ ๋ค์ด๊ฐ์๊ฐ ์์ด์, ์ด๋ฐ ๋ฌธ์ ๋ค์ด ๋ด์๋๋ค.
~cpp
class ColorPrinter: public Printer {
...
};
~cpp Printer p; ColorPrinter cp;
~cpp
class CPFMachine { // copy, print, fax ์ ๋ถ ํ ์ ์๋ ๊ธฐ๊ณ
private:
Printer p; // ํ๋ฆฌํฐ ๊ธฐ๋ฅ์ ์ธ์.
FaxMachine f; // ํฉ์ค ๊ธฐ๋ฅ์ ์ธ์
CopyMachine c; // ๋ณต์ฌ๊ธฐ ๊ธฐ๋ฅ์ ์ธ์.
...
};
CPFMachine m1; // ์ฌ๊ธฐ ๊น์ง๋ ์๋๋ค.
CPFMachine m2; // TooManyObjects ์์ธ๋ฅผ ๋ฐ์ ์ํจ๋ค.
์, ์ด๋ฐ๊ฑธ๋ก ํ๊ฐ์ง ์ฌ๋ฏธ์๋ ๊ฒ์ ๋ง๋ค์ ์๋ค. ๋ง์ฝ ๋น์ ์ด C++์์์ ๋์ด์ ์์ ๋์ง ์๋ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ ์ถ์๋ ์ด๋ป๊ฒ ํด์ผ ํ ๊น?(์ฃผ:์ฐธ๊ณ ๋ก Java๋ C#์ ๊ฒฝ์ฐ ์ธ์ด ์ค๊ณ ๋๋ถํฐ ์์ ํด๋น ๊ธฐ๋ฅ์ ์ํ์ ์ํ ํค์๋๋ฅผ ์ ๊ณตํ๋ค. ํ์ง๋ง C++๋ ์ ๊ณตํ์ง ์๋๋ค. ์ด๋ฐ ๋ฐฉ๋ฒ์ ์ค๊ณ์๊ฐ ์๊ฐํ๊ฑด์ง, ์ฐจํ C++์ ๊ฐ๋ฐ์๋ค์ด ์๊ฐํ๊ฑด์ง ๋๋ผ์ธ ๋ฟ์ด๋ค. ๋ฐ๋ก ์ด์ ์ ๋์จ ๊ฐ์ ๋ณต์ฌ ์์ฑ์์ ์์ด๋์ด์ ๋น์ทํ๋ค๊ณ ํด์ผ ํ ๊น)
์ด๋ ๊ฒ ์์ฑ์๊ฐ ์ฌ์ญ(private)์ธ์๋ก ๋ค์ด๊ฐ ๋ฒ๋ฆฌ๋ฉด, ํด๋น ํด๋์ค์์ ์ ๋๋๋ ํด๋์ค๋ฅผ ๋ง๋ค๊ธฐ๋ ๋ถ๊ฐ๋ฅ ํ๋ค. ํ์ง๋ง ์ด ์ฝ๋์ ๋ฌธ์ ์ ์ makeFSA๋ฅผ ์ด์ฉํด ์์ฑํ๋ฉด ํญ์ delete๋ฅผ ํด์ฃผ์ด์ผ ํ๋ค๋ ์ ์ด๋ค. ์ด์ ์์ธ๋ฅผ ๋ค๋ฃจ๋ ๋ถ๋ถ์์๋ ์ธ๊ธํ์ง๋ง, ์ด๋ ์์์ด ์ธ๋๊ฐ ์ฌ์ง๋ฅผ ๋จ๊ธฐ๋ ๊ฒ์ด๋ค. ์ด๋ฅผ ์ํ STL์ auto_ptr๋ ์ฐธ๊ณ ํ์.(Item 9 ์ฐธ๊ณ )
~cpp
class FSA {
public:
// ๊ฐ์ง ์์ฑ์๋ค
static FSA * makeFSA(); // ์์ฑ์
static FSA * makeFSA(const FSA& rhs); // ๋ณต์ฌ ์์ฑ์
...
private:
FSA();
FSA(const FSA& rhs);
...
};
FSA * FSA::makeFSA()
{ return new FSA(); }
FSA * FSA::makeFSA(const FSA& rhs)
{ return new FSA(rhs); }
~cpp // ๊ธฐ๋ณธ ์์ฑ์ auto_ptr<FSA> pfsa1(FSA::makeFSA()); // ๋ณต์ฌ ์์ฑ์ auto_ptr<FSA> pfsa2(FSA::makeFSA(*pfsa1)); ... // ์ ์ด์ ํด๋น ์์ญ์ ๋ฒ์ด๋๋ฉด ๊ฐ์ฒด๋ ์๋ ํ๊ดด๋๋ค.
1.2.3. Allowing Objects to Come and Go : ๊ฐ์ฒด๊ฐ ์ค๊ณ ๊ฐ์ ํ์ฉํ๊ธฐ? ¶
์ด์ , ๋จ์ผํ ๊ฐ์ฒด ๋ง๋ค๊ธฐ ๋ฐฉ๋ฒ์ ๊ดํ ๋์์ธ ๋ฐฉ๋ฒ์ ์์ ์์ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ , ๊ฐ์ฒด๋ฅผ ์ซ์๋ก ์ ์ดํ๋ ๊ฒ์ ์ธ๊ฐ์ง์ ์์ฑ ์ํฉ์ ์ํด์ ํญ์กํ ์ํฉ์ ๋ง๋ค์ด ๋๊ฐ๋ค๋ ๊ฒ์ ์๊ฒ์ด๋ค. ์ด๊ฒ์ ์ํด์ ์์ฑ์์ ์ฌ์ญ(private)์ญ์ ์ค๋ช
ํ๋ค. ์บก์ํ๋ thePrinterํจ์๋ Printer๋ผ๋ ๋จ์ผํ ๊ฐ์ฒด๋ฅผ ์ ํํ๊ณ , ๊ทธ๊ฒ์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ค. thePrinter๊ฐ ๋์์ผ๊น. ํ์ง๋ง ๊ฒฐ๊ตญ thePrinter๋ C++์ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ธ ์ด๋ฌํ ๋์์ธ์ ์ฝ๋๋ฅผ ๋ถ๊ฐ๋ฅํ๊ฒ ํ๋ค.
์ด๋ฐ ๋์์ธ์ ๋จ์ผ Printer๊ฐ์ฒด์ ๊ดํด์ ํํ์ฌ ์ง์๋ ์๋ค. ํ์ง๋ง ์๋ก ๋ค๋ฅธ ํ๋ก๊ทธ๋จ์ ์๋ก ๋ค๋ฅธ ๋ถ๋ถ์์ Printer๊ฐ์ฒด๋ ์ด๋ ๊ฒ ์ฌ์ฉ๋์ด ์ง์ ์๋ค. ์ด๊ฒ ์ญ์ ํ์ฉํ์ง ๋ชปํ๊ฒํ๋ ๊ฒ๊น์ง๋ ํ์ ์์๊ฒ ๊ฐ์๋ฐ, ์๋ฌดํผ ์ค์ง ํ๋์ ํ๋ฆฐํฐ ๊ฐ์ฒด๋ง ์ ์ง ์ํจ๋ค๋ ๊ฒ์๋ ๋ฒ์ด๋์ง๋ ์๋ ๊ฑฐ๋ค. ํ์ง๋ง ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๊ฐ ํด์๋ object-counting๋ฐฉ๋ฒ๊ณผ, ์ผ์ฐ์ด ์ด ๊ฐ์ง ์์ฑ์(pseudo-constructor)๋ฅผ ํผํฉํด์ ๊ธฐ๋ฅ์ ๊ตฌํํด ๋ณธ๋ค.
๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ ์ด๋ ๊ฒ ์ฌ์ฉํด์ผ๋ง ํ๋ค.
์ด๋ฌํ ๊ธฐ์ ์ ์ด๋ ํ ์ซ์์ ๊ฐ์ฒด์ ์ ํ์๋ ์จ๋จน์์ ์๋๋ฐ, ๋ค์๊ณผ ๊ฐ์ ์ฝ๋ฉ์ผ๋ก ๊ฐ๋ฅํ๋ค ๋ค์์ ๊ฐ์ฒด๋ฅผ 10๊ฐ๋ก ์ ํ ์์ผ๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค.
๊ฐ์ ์ฝ๋ ์จ์ ๋ด์ฉ๋ง ๋๋ฆฐ ๊ฒ ๊ฐ๋ค. ํ์ง๋ง ์กฐ๊ธ๋ ์ธ๊ธํด ๋ณธ๋ค๋ฉด. Printer::maxObjects๋ ํด๋์ค ๋ด๋ถ์์ 10์ผ๋ก ์ด๊ธฐํ ์์ผฐ๋๋ฐ, ์ด๋ ์ปดํ์ผ๋ฌ์ ์ง์ ์ฌ๋ถ์ ๋ฐ๋ผ static const ๋ฉค๋ฒ์ ๊ฒฝ์ฐ ์ด๊ธฐํ๊ฐ ๊ฐ๋ฅํ C++์ ๊ท์น์ด๋ค.(์ฃผ:์ฐธ๊ณ ๋ด์ฉ์ด ์์๋๋ฐ ๋ช ์ฅ์ธ์ง ๊ธฐ์ต ์๋๋ค.) ๊ทธ๋ฆฌ๊ณ maxObject์ ๊ดํ์ฌ ๋ณํ์ง ์๋ ๊ฐ์ด๊ธฐ์ enum์ผ๋ก๋ ์ธ์ ์๋๋ฐ, ๋ค์๊ณผ ๊ฐ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง์ฝ์ ํ์ฌ ์ปดํ์ผ๋ฌ๊ฐ ํด๋์ค ๋ด๋ถ์์ ์ด๊ธฐํ๋ฅผ ํ์ฉํ์ง ์๋๋ค๋ฉด ์ด๋ ๊ฒ ์จ์ ํด๊ฒฐํ๋ผ.
์์ ๋๋ค ์๋จ์ ์ฝ๋์ ๋์ผํ ์ญํ ์ ํ๋ ๊ฒ์ด๋ค. ์ข์ ์ปดํ์ผ๋ฌ ์ฐ์๊ธธ..
~cpp create Printer object p1; use p1; destroy p1; create Printer object p2; use p2; destroy p2;
~cpp
class Printer {
public:
class TooManyObjects{};
static Printer * makePrinter(); // ๊ฐ์ง ์์ฑ์(pseudo-constructors)
~Printer();
void submitJob(const PrintJob& job);
void reset();
void performSelfTest();
...
private:
static size_t numObjects;
Printer();
Printer(const Printer& rhs); // ๋ค์๊ณผ ๊ฐ์ ํจ์๋ ๋ณต์ฌ ๋ฐฉ์ง๋ฅผ ์ํด
// ๊ตฌํ ๋์ง ์๋๋ก ํ๋ค. ( E27์ฐธ๊ณ ) DeleteMe)๊ฒ์ฆํ์
};
// ํด๋์ค์ static์ ์ ์(definition,๋น์ทํ๊ฒ ์ด๊ธฐ๊ฐ ๊ตฌํ)์ ๋ฐ๋์ ํด์ผ ํ๋ค.
size_t Printer::numObjects = 0;
Printer::Printer()
{
if (numObjects >= 1) {
throw TooManyObjects();
}
๋ณดํต์ ์์ฑ ๊ณผ์ ์ ์ํํ๋ค.
++numObjects;
}
Printer * Printer::makePrinter()
{ return new Printer; }
~cpp
Printer p1; // ์์ฑ์๊ฐ ์ฌ์ญ(private)์ด๋ฏ๋ก
// ์๋ฌ๋ฅผ ๋ฐ์ ์ํจ๋ค.
Printer *p2 = Printer::makePrinter(); // ์ฌ๋ฐ๋ฅด๋ค. ์ด๊ฒ์ด ๊ธฐ๋ณธ ์์ฑ์์ด๋ค.
Printer p3 = *p2; // ์๋ฌ! ๋ณต์ฌ ์์ฑ์ ์ญ์ ์ฌ์ญ์ผ๋ก ์ค์ ๋์ด ์๋ค.
p2->performSelfTest(); // ๊ฐ์ฒด ์ฌ์ฉํ๋ฏ์ด ํ๋ค.
p2->reset(); // ๋ง์ฐฌ๊ฐ์ง
...
delete p2; // ์์์ด ์ธ๋๊ฐ์ง ์๊ธฐ์ํด ์ ๊ฑฐ ํด์ค๋ค.
// auto_ptr์ ์ฐ๋ฉด ์ด๋ ํ์ ์์ด ์ง๋ค.
~cpp
class Printer {
public:
class TooManyObjects{};
static Printer * makePrinter(); // // ๊ฐ์ง ์์ฑ์(pseudo-constructors)
static Printer * makePrinter(const Printer& rhs);
...
private:
static size_t numObjects;
static const size_t maxObjects = 10; // ์๋ ์ฐธ๊ณ
Printer();
Printer(const Printer& rhs);
};
// ํด๋์ค์ static์ ์ ์(definition,๋น์ทํ๊ฒ ์ด๊ธฐ๊ฐ ๊ตฌํ)์ ๋ฐ๋์ ํด์ผ ํ๋ค.
size_t Printer::numObjects = 0;
const size_t Printer::maxObjects;
Printer::Printer()
{
if (numObjects >= maxObjects) {
throw TooManyObjects();
}
...
}
Printer::Printer(const Printer& rhs)
{
if (numObjects >= maxObjects) {
throw TooManyObjects();
}
...
}
Printer * Printer::makePrinter()
{ return new Printer; }
Printer * Printer::makePrinter(const Printer& rhs)
{ return new Printer(rhs); }
~cpp
class Printer {
private:
enum { maxObjects = 10 }; // ์์ 10 ์ ํ๊ณผ ๊ฐ์ ์ญํ ์ ํ๋ค.
};
~cpp
class Printer {
private:
static const size_t maxObjects; // ์๋ฌด๋ฐ ์ด๊ธฐํ๋ฅผ ํ์ง ์๋๋ค.
...
};
// ์ฌ๊ธฐ์์ ๋ค์๊ณผ ๊ฐ์ด ์ด๊ธฐํ๊ฐ ๊ฐ๋ฅํ๋ค.
const size_t Printer::maxObjects = 10;
1.2.4. An Object-Counting Base Class : Object-counting์ ๊ธฐ๋ณธ ํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ณธ๋ค. ¶
์ด์ ๊น์ง ๊ฑฐ์ณ์๋ ์ฝ๋๋ค์ ์ด๋ ์ ๋์ ํํ๊ฐ ์กํ ์๋ค. ์ด๊ฒ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ง๋ค์ด ๋๊ณ , ์ผ์ ํ ๊ท์น์ผ๋ก ๋ง๋ค์๋ ์์๊น? (์ฐธ๊ณ ๋ก ์ด์ ๋น์ทํ ๊ธฐ์ ์ด Item 29 reference-counting์ ๋ฑ์ฅํ๋ค. ์ฐธ๊ณ ํด๋ณด์.) template๊ฐ ์ด๋ฅผ ๊ฐ๋ฅํ๊ฒ ํด์ค๋ค.
๋ค์๊ณผ ๊ฐ์ template๋ฅผ ์ด์ฉํด์
ํด๋น ํด๋์ค๋ ์ค์ง ๊ธฐ๋ณธ ํด๋์ค๋ก๋ง ์ฐ์ด๋๋ก ์ค๊ณ๋์ด ์ก๋ค. ๊ทธ๋ฌ๋ฏ๋ก, ์์ฑ์์ ํ๊ดด์๊ฐ ๋ชจ๋ protected(๋ณดํธ)์ธ์๋ก ์ค์ ๋์ด ์๋ค. ๊ทธ๋ฆฌ๊ณ init๋ก์ object-counting์ ๊ตฌํํ๋ค. init๋ ์ค์ ๋ ๊ฐ์ฒด์ ์ซ์๊ฐ ๋์ด๊ฐ๋ฉด, TooManyObjects ์์ธ ๊ฐ์ฒด๋ฅผ ๋ฐ์ ์ํจ๋ค.
~cpp
template<class BeingCounted>
class Counted {
public:
class TooManyObjects{}; // ๋์ง ์์ธ
static int objectCount() { return numObjects; }
protected:
Counted();
Counted(const Counted& rhs);
~Counted() { --numObjects; }
private:
static int numObjects;
static const size_t maxObjects;
void init(); // ์์ฑ์์ ์ฝ๋ ์ค๋ณต์ ํผํ๋ค.(์ด์ฐจํผ ๊ฐ์ ์ฝ๋ ์ฐ๋๊น.)
};
template<class BeingCounted>
Counted<BeingCounted>::Counted()
{ init(); }
template<class BeingCounted>
Counted<BeingCounted>::Counted(const Counted<BeingCounted>&)
{ init(); }
template<class BeingCounted>
void Counted<BeingCounted>::init()
{
if (numObjects >= maxObjects) throw TooManyObjects();
++numObjects;
}
์ด์ ์์ template๋ฅผ ๋ฐํ์ผ๋ก ๊ธ ์ด๋ฐ์ ๋๋ํ ์ค๋ช
ํ object-counting์ ๊ธฐ๋ฐํ Printerํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ณธ๋ค.
์ดํด๊ฐ ์๊ฐ๋ ๋ถ๋ถ์ ์ญ์๋ using์ด ์ฐ์ธ ๊ณณ๊ณผ private๋ก ์์ ๋์๋ค๋ ์ ์ผ ๊ฒ์ด๋ค.
~cpp
class Printer: private Counted<Printer> {
public:
static Printer * makePrinter(); // ๊ฐ์ง ์์ฑ์(pseudo-constructors)
static Printer * makePrinter(const Printer& rhs);
~Printer();
void submitJob(const PrintJob& job);
void reset();
void performSelfTest();
...
using Counted<Printer>::objectCount; // ์ ์ฌ์ฉํ๋์ง ์๋ ์ฐธ๊ณ
using Counted<Printer>::TooManyObjects; // ๋ง์ฐฌ๊ฐ์ง~
private:
Printer();
Printer(const Printer& rhs);
};
private๋ฅผ ๋จผ์ ์ค๋ช
ํด ํ๋ค. ๊ฒฐ๋ก ๋ถํฐ ์ด์ผ๊ธฐํ๋ฉด ์ํ์ฑ ์ ๊ฑฐ์, ํฌ๊ธฐ์ ์ต์ ํ๋ฅผ ์ํด์ ์ด๋ค. ๋ค๋ฅธ ์ด๊ฐ Counted<Printer> ํฌ์ธํฐ๋ฅผ ํตํด์ Printer๊ฐ์ฒด๋ฅผ ์ ๊ฑฐํ๋ ค๋ ์๋๋ฅผ ํ ์ง๋ ๋ชจ๋ฅธ๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ณ , private์์์ Item 24์ ๋ช
๋ฐฑํ ๋์ ์๋ฏ์ด Counted๋ด์ ๊ฐ์ ํจ์๊ฐ ์กด์ฌ ํ๋๋ผ๋, Printer์์ ํด๋น ๊ฐ์ ํจ์์ ๋ํ vtbl์ ์์ฑํ์ง ์์ผ๋ฏ๋ก์ overhead๋ฅผ ์ค์ธ๋ค.
using์ ์จ์ Counted์ ์กด์ฌํ๋ ์ธ์๋ฅผ ์ฐธ์กฐ ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ์ด์ ๋ Printer์
์ฅ์์ ๋ค๋ฅธ ์ธ์๋ค์ ์ ๊ฒฝ ์ธํ์๊ฐ ์์ง๋ง, ๋ช๋ช ํน์ ํ ์ธ์์ ์ฐธ์กฐ์, ์ฌ์ฉ์ ํ๊ธฐ ์ํด์ ์ด๋ค. objectCount๋ ์๋์ ์ฃผ์๋ฌธ์ ์ด์ ์ด๊ณ ,
๋ง์ฝ, using์ ์ง์ํ์ง ์์ ์ปดํ์ผ๋ฌ๋ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์๋ ๋ฌธ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
์ด๋ using์ด ์กด์ฌ ํ์ง ์์์๋ ์ฌ์ฉ๋ ์๋ ๋ฌธ๋ฒ์ด๋ค. TooManyObjects ํด๋์ค ์ญ์ ๊ฐ์ ์ด์ ๋ก using์ ์ด์ฉํด์ ์ด๋ฆ์ ์ฌ์ฉํ๊ฒ ๊ถํ์ ์ด์์ผ๋ฉฐ, ์ด๋ ๊ฒ TooManyObjects๋ฅผ ํ์ฉํด์ผ ์ง๋ง ํด์ผ์ง๋ง ํด๋ผ์ด์ธํธ๋ค์ด ํด๋น ์์ธ๋ฅผ ์ก์ ์ ์๋ค.
~cpp
class Printer: private Counted<Printer> {
public:
...
using Counted<Printer>::objectCount; // ์ด ํจ์๋ก ํ์ฌ ๊ฐ์ฒด์ ์ซ์๋ฅผ ์์ ์๋ค.
... // ์ด๊ฑฐ ํจ์๋ค. ์ฐฉ๊ฐ ๋ง์๊ธธ. Counted ํด๋์ค๋ฅผ ํ๋ฒ ์ดํด๋ณด๋ผ.
};
~cpp
class Printer: private Counted<Printer> {
public:
...
Counted<Printer>::objectCount; // ์ด ํจ์๋ก ํ์ฌ ๊ฐ์ฒด์ ์ซ์๋ฅผ ์์ ์๋ค.
... // ์ด๊ฑฐ ํจ์๋ค. ์ฐฉ๊ฐ ๋ง์๊ธธ. Counted ํด๋์ค๋ฅผ ํ๋ฒ ์ดํด๋ณด๋ผ.
};
์์ฑ์์์ ๊ฐ์ํ ๊ฒ์ ์๋ค. ๊ทธ๋ฅ ์ผ๋ฐ์ ์ธ ์์ฑ๊ณผ์ ์ ๊ธฐ์ ํด ์ฃผ๋ฉด ๋ฌด๋ฆฌ๊ฐ ์์ผ๋ฉฐ, ํ์ํ ์์
์ Counted<Printer>์ ์์ฑ์์์ ํ๊ธฐ๋๋ฌธ์ Printer์ ์์ฑ์๋ ๋ค์๊ณ ๊ฐ๋ค.
Printer์ ์์ฑ์์์๋ ๊ฐ์ฒด๋ฅผ ์ ๊ฒํ๋ ์ฝ๋๊ฐ ๋ค์ด๊ฐ์๋ ์๋๋ค. ์๋ํ๋ฉด, Counted<Printer>์์ ์ ๊ฒํ๊ณ ์ด์ ์์ด์ ์์ธ๋ฅผ ๋์ง๋ค๋ฉด, ๋ค์์ ๋ถ๋ฆด Printer์์ฑ์๋ ์์ ๋ถ๋ฆฌ์ง๋ ์๋๋ค. ์๊ฒ ๋?
~cpp
Printer::Printer()
{
์ผ๋ฐ์ ์ธ ์์ฑ์ ๊ณผ์
}
๋ ํ๋๋ object-counting์์ ์ด๊ธฐ๊ฐ์ด๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ด๊ธฐํ๊ฐ ๋๋ค.
DeleteMe) ์ด๊ฒ์ด ๋๋ ๊ณผ์ ๋ ์ ํํ ์ดํด๊ฐ ๊ฐ์ง ์๋๋ค. ๋๋๊ฑฐ์๋ ์ฌํ? ๊ณ ๋ฏผ๋๋ค.
~cpp template<class BeingCounted> int Counted<BeingCounted>::numObjects; // ๊ฐ์ฒด์ ์ ์ธ๊ณผ, ์๋์ผ๋ก 0์ผ๋ก ์ด๊ธฐํ๊ฐ ๋๋ค.
maxObjects์ ์ด๊ธฐํ ์ญ์ ๋ฌธ์ ๋ก ๋๋ ๋๋๋ฐ, ๋ค์๊ณผ ๊ฐ์ด ์ด๊ธฐํ ์ํจ๋ค.
๋ง์ฝ FileDescriptor๊ฐ ์ ๋๋ ํด๋์ค๋ผ๋ฉด ์ด๋ ๊ฒ ํ๋ค.
์ด๋ ๋น๋ก ํด๋น ๊ฐ์ฒด๊ฐ private๋ก ์์ ๋ฐ์์ง๋ง, ์ ๋๋ ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋ ๋ค์๊ณผ ๊ฐ์ด ์ด๊ธฐํ๋ฅผ ์ํฌ์ ์๋ค. ์ด๊ธฐํ ๋ฆฌ์คํธ์ ๋น์ทํ๋ค๊ณ ํด์ผ ํ ๊น?
~cpp const size_t Counted<Printer>::maxObjects = 10;
~cpp const size_t Counted<FileDescriptor>::maxObjects = 16;
1.3. Item 27: Requiring or prohibiting heap-based objects. ¶
- Item 27: Heap์์ญ์ ์ฌ์ฉํ๋ ๊ฐ์ฒด ์๊ตฌํ๊ธฐ or ํผํ๊ธฐ.
๋๋ก ์์ด์ ํ์ฉํด์ผ ํ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๋๋ ์๋ค. ํํ์ด ๊ฒฉํ๊ฐ? "delete this"๋ฐ์ ๊ฐ์ด ๋ง์ด๋ค. ์ด๋ฌํ ๊ฐ์ฒด๋ heap์์ญ์ ๋ฐฐ์น ๋๋๋ฐ, ํ์คํ๊ฒ ์ ๊ฑฐ๋ง ํด์ค๋ค๋ฉด ์์์ด ์ ์ด์ ๋ ์๋ค. ๊ทธ๋ ๋ค. ์ฃผ์ ๊น๊ฒ ๋ค๋ฃจ์ด์ผ ํ๋ ๊ฐ์ฒด๋ค์ด๋ค. embedded system๊ฐ์ด ์ด์ ํ ํ๊ฒฝ์์ ์ด๋ค์ ์๋ชป๋ค๋ฃจ์ด์ ์ผ์ด๋ ์ค์๋ ์น๋ช ์ ์ธ ์์์ ๋ถ๋ฅธ๋ค. ์ด์ ํ๋ํ๋ heap์์ญ์ ๊ด๋ จํ ๋ด์ฉ์ ๋ค๋ฃฌ๋ค.
1.3.1. Requiring Heap-Based Objects : Heap ๊ธฐ๋ฐ ๊ฐ์ฒด๋ค์ด ํ์ ¶
์ฐ์ ๊ฐ์ฒด๋ฅผ Heap์์ญ ์์์๋ง ์์ฑ๋๊ณ ์ฌ์ฉํ๋ ๊ฐ์ฒด๋ก ์ ํํ๋ ๊ฒ์ ๊ดํด์ ์๊ฐํด ๋ณด์. Heap์์ญ์ ์๋ฆฌ๋ฅผ ์ฐจ์งํ๋ ๊ฐ์ฒด๋ ๋ชจ๋ new๋ฅผ ํธ์ถํด์ ํ์๋ฆฌ์ฉ ํ๋, ๋ญ, ๊ฐ๋จํ new๋ฅผ ๋ง์ ๋ฒ๋ฆฌ๋ฉด ๋๋๊ฒ์ด๋ค. ๊ทธ๋ ๋ค๋ฉด ๋ฐ๋๋ก Heap์์ญ์ด ์๋ ๊ฐ์ฒด๋ค์ ๋ชจ๋ new๋ฅผ ํธ์ถํ์ง ์๊ณ , ์๋์ผ๋ก ๋ฌต์์ ์์ฑ๋๊ณ , ๋ฌต์์ ํ๊ดด๋์ด ์ง๋ค๋ ์๋ฏธ๊ฐ ๋ใ
๋ค.
Item 26์ ๋ค๋ฃฌ๊ฒ๊ณผ ๊ฐ์ด ์์ฑ์์ ํ๊ดด์๋ฅผ ์ฌ์ญ(private)๋ก ๋ฌถ์ด ๋ฒ๋ฆฌ๋ ์์ด๋์ด๊ฐ ๊ฐ์ฒด ์์ฑ ์ ํ์ ์์์ด ๋ ์ ์์ ๊ฒ์ด๋ค. ํ์ง๋ง, ๋๋ค ๋ฌถ์ด ๋ฒ๋ฆฌ๋๊ฑด ๋๋ฌด ๊ณผ์์ด๋ค. ๊ทธ๋ฅ ํ๊ดด์๋ง์ ์ฌ์ญ(private)๋ก ๋ฌถ์ด ๋ฒ๋ฆฌ๊ณ , ์์ฑ์๋ ๊ณต์ญ(public)์ผ๋ก ๋์๋ ํจ๊ณผ๋ ๋น์ทํ๋ค. ๋ค์์ ์์ ๋ฅผ ๋ณด์.
ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ ๊ฒ ์ ์ธ๋ ํด๋์ค๋ฅผ ๊ธฐ๋ฐํ ๊ฐ์ฒด์ ์ฌ์ฉ์ ์์ ๋ณด์๋ฉด
์ ๋ค์๊ณผ ๊ฐ์ด, UPNumber ํด๋์ค๋ Heap์์์๋ง ์ฌ์ฉํ ์ ์๋ ๊ฐ์ฒด๋ง์ ์์ฑ ํ ์ ์๋ค. ์ด๊ฒ์ ๋์์ผ๋ก๋ Item 26 ๋ง์ง๋ง์ ๋์จ ์์ ์ ๊ฐ์ด ๋ชจ๋ ์์ฑ์ ๋ง์ ์ฌ์ญ(private)ํ ์ํค๋ ๊ฒ์ด์ง๋ง, ์ด ์์ด๋์ด์ ๋ฌธ์ ๋ ๋ง์ ์์ฑ์๊ฐ ๋ชจ๋ ์ฌ์ญ(private)์ผ๋ก ์์ด์ผ ํ๊ณ , ๊ทธ๊ฒ๋ค์ ๋ฐ๋์ ๊ธฐ์ตํด์ผ ํ๋ค๋ ์ ์ด๋ค. ๊ธฐ๋ณธ ์์ฑ์๋ ๋ฌผ๋ก , ๋ณต์ฌ ์์ฑ์๋ฅผ ์ ๋ถ ์ ์ธํด ์ฃผ์ด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ปดํ์ผ๋ฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๊ณต์ญ(public)์ผ๋ก ์ทจ๊ธํ๊ณ ์ง์ญ ๋ณ์๋ฅผ ๋ง๋ค์ ์๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก, ํ๊ดด์๋ง์ ์ฌ์ญ(private)ํ ์ํค๋ ๊ฒ์ด ๊ฐ๋จํ๋ค.
~cpp
class UPNumber {
public:
UPNumber();
UPNumber(int initValue);
UPNumber(double initValue);
UPNumber(const UPNumber& rhs);
// ๊ฐ์ง ํ๊ดด์(pseudo-destructor) ์์ ๋ฉค๋ฒ ๋ฉ์๋,
// ์์ ๊ฐ์ฒด๋ฅผ ์ ๊ฑฐ ํ ์ ์๊ฒ ํ๊ธฐ ๋๋ฌธ์
void destroy() const { delete this; }
...
private:
~UPNumber(); // ํ๊ดด์๊ฐ ์ฌ์ญ(private)์ผ๋ก ์ ์ธ๋์๋ค.
};
~cpp UPNumber n; // ์๋ฌ! ํ๊ดด์ ์ฌ์ญ(private)์ด๋ผ ์๋ ํ ์ ์๋ค. UPNumber *p = new UPNumber; // ํต๊ณผ ... delete p; // ์๋ฌ! ์ญ์ ํ๊ดด์ ์ฌ์ญ(private) ์ด์ p->destroy(); // ํต๊ณผ
ํด๋์ค์ ์์ฑ์์, ํ๊ดด์ ์์ชฝ์ ์ฌ์ญํ(private)์์ผ์ ์ง์ญ ๊ฐ์ฒด(non-heap object)๋ก ๋ง๋๋๊ฑธ ๋ง๋๋ฐ๋, ์ฝ๊ฐ์ ์ ํ ์ฌํญ์ด ๋ฐ์ํ๋ค. ๊ทธ ์ ํ์ฌํญ์ด๋, ์์ ๊ด๊ณ์ ํฌํจ(containment:has-a)๊ด๊ณ์์ ๋ฐ์ํ๋ค. ๋ค์์ ์์ ๋ฅผ ๋ณด๋ฉด.
์ด๋ฐ ๋ฌธ์ ๋ ํด๊ฒฐํ๊ธฐ ์ด๋ ต์ง ์ํ. ์์ ๊ด๊ณ์ ๋ฌธ์ ๋ ์์ฑ์๋ ๊ณต์ญ(public)์ผ๋ก ์ ์งํ๊ณ , ํ๊ดด์๋ง์ ๋ณดํธ(proteced) ๊ด๊ณ๋ก ๋ฐ๊พธ๋ฉด ๋๋๊ฒ์ด๊ณ , ํฌํจ(contain) ๊ด๊ณ์์๋ ํด๋น ํฌํจ ์ธ์๋ฅผ pointer๋ก ๋ฐ๊พธ๊ณ , ์ด๊ธฐํ ๋ฆฌ์คํธ์์ ์์ฑํด ๋ฒ๋ฆฌ๊ณ , ํ๊ดด์์์ ์ฝ๊ฐ๋ง ์ ๊ฒฝ์จ์ฃผ๋ฉด ๋๋ค. ์์ ์ฝ๋์ ํด๊ฒฐ์ฑ
์ ๋ค์๊ณผ ๊ฐ๋ค.
~cpp
class UPNumber { ... }; // ์์ฑ์์ ํ๊ดด์ ๋ชจ๋ ์ฌ์ญ(private)๋ก
//์ ์ธ๋์๋ค๊ณ ๊ฐ์ ํ๋ค.
class NonNegativeUPNumber:
public UPNumber { ... }; // ์๋ฌ! ์์ฑ์์ ํ๊ดด์๋ฅผ ์ปดํ์ผ ๋ชปํ๋ค.
class Asset {
private:
UPNumber value; // ์๋ฌ! ์์ฑ์์ ํ๊ดด์๋ฅผ ์ปดํ์ผ ๋ชปํ๋ค.
...
};
~cpp
class UPNumber { ... }; // ํ๊ดด์๋ฅผ ๋ณดํธ(protected)๋ก ์ค์ ํ๋ค.
// ๋์ ์์ฑ์๋ ๊ณต์ญ(public)์ผ๋ก ์ค์ ํ๋ค.
// ๊ธฐ๋ฅ์ ์๊ด ์์ผ๋ฏ๋ก
class NonNegativeUPNumber:
public UPNumber { ... }; // ์ด์ ๋ ์ ๋๋๋ ๋ฐ๋ ์ง์ฅ ์๋ค.
// ์ ๋๋๋ ํด๋์ค๋ค์ protected์ธ์๋
// ์ ๊ทผํ๋๋ฐ ๋ฌธ์ ๊ฐ ์๋ค.
class Asset {
public:
Asset(int initValue);
~Asset();
...
private:
UPNumber *value; // ์์์์ ๊ฐ์ฒด ์ ์ธ์ ํฌ์ธํฐ๋ก ๋ฐ๊พธ์๋ค.
};
Asset::Asset(int initValue)
: value(new UPNumber(initValue)) // ๋ค์๊ณผ ๊ฐ์ด ์ด๊ธฐํ ๋ฆฌ์คํธ๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ
{ ... }
Asset::~Asset()
{ value->destroy(); } // ํ๊ดด์์ ์ ๊ฒฝ์จ์ค๋ค.(resource leak๋ฐฉ์ง)
1.3.2. Determining Whether an Object is On The Heap : Heap์ ๊ฐ์ฒด๋ฅผ ์ฌ๋ฆด์ง ๊ฒฐ์ ํ๊ธฐ. ¶
์, ์ง๊ธ๊น์ง ๋ค์ ๋งน๋ชฉ์ (?)์ผ๋ก Heap์์ญ์ ๊ฐ์ฒด ์ฌ๋ฆฌ๊ธฐ์๋ง ์ด์คํ๋ค. ๊ทธ๋ผ ์ฌ๊ธฐ์์๋ "on the heap"์ ์๋ฏธ๋ฅผ ํ์คํ ํ
์คํธ๋ก์ ์์ ๋ณด๋๋ก ํ๊ฒ ๋ค. ์์ ์จ๋จน์ NonNegativeUPNumber๋ฅผ non-heap ๊ฐ์ฒด๋ก ๋ง๋๋๊ฑด ๋ญ ํ๋ฆฌ์ง ์์ ๊ฒ์ด๋ค.
์ด๊ฒ์ด ํ์ฉ๋๋ค๋ ๊ฒ์ด๋ค. ์, ๊ทธ๋ผ ์ง์ญ ๊ฐ์ฒด์ธ NonNegativeUPNumber์ n์์ UPNumber์ ๋ถ๋ถ์ heap์์ ์๋ ๊ฒ์ด ์๋๋ค. ๋ง๋๊ฐ? ์ด ๋ต๋ณ์ ํด๋์ค์ ์ค๊ณ(design)๊ณผ ์ ์ฉ(implementation)์ ๊ธฐ์ธํด์ผ ์ดํด ํ ์ ์์ ๊ฒ์ด๋ค. ๋ต์ ์ฐพ์๊ฐ ๋ณด์.UPNumber๊ฐ ๋ฐ๋์ heap์์ญ์ ์กด์ฌ ํด์ผ ํ๋ค๋ ๊ฒ์ ๊ดํด not okay๋ฅผ ๋์ง๋ฉด์ ์์ํด ๋ณด์. ์ด๋ป๊ฒ ์ฐ๋ฆฌ๋ ์ด๋ฌํ ์ ํ ์ฌํญ์ ํด๊ฒฐํด์ผ ํ๋ ๊ฑธ๊น?
~cpp NonNegativeUPNumber n; // fine
์ด๊ฒ์ ๊ทธ๋ฆฌ ์ฝ์ง ์๋ค. UPNumber ์์ฑ์๊ฐ ์ด๊ฒ์ ์ ๋ ๋ฐ์ ๋ชจ๋ ๊ฐ์ฒด์๊ฒ, Heap์์ญ ๊ธฐ๋ฐ์ ๊ฐ์ฒด๋ก ๋ง๋ค์ด ๋ฒ๋ฆฌ๋ผ๊ณ ๊ฒฐ์ ํ๋๊ฒ์ ๊ฐ๋ฅํ์ง ์๋ค. ๊ธฐ๋ณธ ํด๋์ค๋ก ์ฐ์ธ UPNumber์ ์์ฑ์๊ฐ ๋ค์์ ๋ ์ํฉ์ ์ฒดํฌํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ค.
๊ทธ๋ ์๋ฏผ ์๋ง ์กฐ๊ธ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ ๊ทผ์ ํ ์ ์๋ค. ๋ฐ๋ก Heap์์ญ์ ์ฌ๋ผ๊ฐ๋ ๊ฐ์ฒด๋ ํญ์ new๋ฅผ ํธ์ถํ๋๊ฒ, ๊ทธ๋ฆฌ๊ณ ์ด new์ ํธ์ถ์ new operator์ operator new์์ ์ํธ ์์ฉ์์ ์์
์ด ์ด๋ฃจ์ด ์ง๋ ๊ฒ์ด๋ค. ์์ธํ ๋ด์ฉ์ Item 8์ ์ฐธ๊ณ ํ๊ณ , ๋ค์๊ณผ ๊ฐ์ด UPNumber๋ฅผ ๊ณ ์ณ์ ์ ๋๋๋ ๊ฐ์ฒด๋ค ๋ง์ ธ ์ ํ์ ๊ฑธ์ ์๋ค.
operator new๋ raw๋ฉ๋ชจ๋ฆฌ ํ ๋น์ ํ๊ณ , ํด๋น ๋ฉ๋ชจ๋ฆฌ์์ ์์ฑ์๋ฅผ ๋ถ๋ฅด๋ฏ๋ก์ ์ด๊ธฐํ๋ฅผ ์ํํ๋ค. operator new์์ onTheHeap์ ์ฐธ์ผ๋ก ์ค์ ํ์ฌ ์ฃผ๋ฉด, ์์ฑ์์์ ์ด๋ฅผ ๊ฒ์ฌํด์ ์์ธ ๋ฐ์์ ํ์ง ์๊ณ , ์ผ๋ฐ ์ง์ญ ๋ณ์๋ก ๊ฐ์ฒด๊ฐ ์ ์ธ๋๋ฉด operator new๋ฅผ ๊ฑฐ์น์ง ์์ผ๋ฏ๋ก, ๊ธฐ๋ณธ ๊ฐ์ธ false์ธํด ์์ฑ์์์ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค.
~cpp NonNegativeUPNumber *n1 = new NonNegativeUPNumber; // Heap์์ญ NonNegativeUPNumber n2; // ๋น Heap์์ญ
~cpp
class UPNumber {
public:
// ๋ง์ฝ non-heap ๊ฐ์ฒด๋ผ๋ฉด ๋ค์์ ์์ธ๋ฅผ ๋ฐ์ ์ํจ๋ค.
class HeapConstraintViolation {};
static void * operator new(size_t size);
UPNumber();
...
private:
static bool onTheHeap; // ์์ฑ์ ๋ด๋ถ์์ heap์์ญ์ ์์ฑ๋๋๊ฐ ํ๋ณ์ธ์๋ก ์ด๋ค.
...
};
// static ์ธ์์ ์ ์ด๊ธฐํ ๋ถ๋ถ
bool UPNumber::onTheHeap = false;
void *UPNumber::operator new(size_t size)
{
onTheHeap = true; // new operator๊ฐ ๋ถ๋ฆฌ๋ฉด Heap์์ญ์ ์ฌ์ฉํ๋๊ฒ.
return ::operator new(size); // operator new๋ก์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋ค.
}
UPNumber::UPNumber()
{
if (!onTheHeap) {
throw HeapConstraintViolation(); // ํ์ด ์๋๋ผ๋ฉด ์์ธ๋ฅผ ๋์ง๋ค.
}
์ผ๋ฐ์ ์ธ ์์ฑ ๊ณผ์ ์ ๊ธฐ์ ํ๋ค.;
onTheHeap = false; // ๊ฐ์ฒด ์์ฑ ํ๋์ค๋ฅผ ์ธํ
ํ๋ค.
}
ํ์ง๋ง ์ด ์ฝ๋๋ค ๋ฅ์ฌ๊ฐ ์๋๊ฒ์ด, ๋ค์๊ณผ ๊ฐ์ ๊ฐ์ฒด์ ๋ฐฐ์ด์ ์ ์ธํ๋ฉด ๋ฌธ์ ๊ฐ ๋๋ค.
์ฒซ์งธ๋ก, ์ด ๊ฒฝ์ฐ operator new๊ฐ ๋ถ๋ฆฌ๋ ๊ฒ์ด ์๋๋ผ. ๋ฉ๋ชจ๋ฆฌ๋ operator new[]๋ก ํ ๋น ๋๊ธฐ๋๋ฌธ์, ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๊ณ , ๋์งธ๋ก operator new[]์ ํ๋๊ทธ ๊ฐ์ ์ฃผ์๋ค๊ณ ํ๋๋ผ๋, ์ฒ์ ํ๋ฒ์ operaotr new[]์ดํ์ ๊ณ์ ์์ฑ์ 100๋ฒ์ด ๋ถ๋ฆฌ๋ฉด์ ์ฒซ๋ฒ์งธ ์์ฑ์์์ ๋ค์ onTheHeap๋ฅผ false๋ก ์ด๊ธฐํ ์ํค๊ธฐ์, ์ดํ์ ๋ถ๋ฆฌ๋ ์์ฑ์๋ ์ ๋ถ onTheHeap์ด false๊ฐ์ผ๋ก ์์ธ๋ฅผ ๋ฐ์ ์์ผ ๋ฒ๋ฆฐ๋ค.
~cpp UPNumber *numberArray = new UPNumber[100];
๋ ๋ฐฐ์ด์ด ์๋๋๋ผ๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ๋ ์๊ฐํด ๋ณธ๋ค.
์ด ๊ฒฝ์ฐ์๋ ๋๊ฐ์ง์ new๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๊ทธ๋ฌ๋ฏ๋ก operator new๋ ๋๋ฒ ๋ถ๋ฆฌ๊ณ ์์ฑ์ ์ญ์ ๋๋ฒ ๋ถ๋ฆด ๊ฒ์ด๋ค. ํ๋ก๊ทธ๋๋จธ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ๊ธฐ๋ํ๋ ๋ค์ ์์์์๋ ์๋ฌด๋ฐ ๋ฌธ์ ๊ฐ ์๋ค. (Item 8 ์ฐธ๊ณ )
~cpp new UPNumber(*new UPNumber);
- operator new๊ฐ ์ฒซ๋ฒ์งธ ๊ฐ์ฒด์ ๊ดํด์ ๋ถ๋ฆฐ๋ค.
- ์ฒซ๋ฒ์งธ ๊ฐ์ฒด์ ์์ฑ์๊ฐ ๋ถ๋ฆฐ๋ค.
- ๋๋ฒ์งธ ๊ฐ์ฒด์ operator new ๊ฐ ๋ถ๋ฆฐ๋ค.
- ๋๋ฒ์งธ ๊ฐ์ฒด์ ์์ฑ์๊ฐ ๋ถ๋ฆฐ๋ค.
- ์ฒซ๋ฒ์งธ ๊ฐ์ฒด์ operator new๊ฐ ๋ถ๋ฆฐ๋ค.
- ๋๋ฒ์งธ ๊ฐ์ฒด์ operator new๊ฐ ๋ถ๋ฆฐ๋ค.
- ์ฒซ๋ฒ์งธ ๊ฐ์ฒด์ ์์ฑ์๊ฐ ๋ถ๋ฆฐ๋ค.
- ๋๋ฒ์งธ ๊ฐ์ฒด์ ์์ฑ์๊ฐ ๋ถ๋ฆฐ๋ค. : ์ฌ๊ธฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
- DeleteMe ์ฃผ์ ๋ณํ์
์ ๋งํ๊ณ ์๋๊ฐ? ๊ทธ๋ผ ํ๋ฒ ์์๋ก๋๋ง ์ด์์ฑ์ด ๋จ์ด์ง๋ ์์ญ์์๊น์ง ๊ทธ๋ฐ ์์ด๋์ด๋ฅผ ํ์ฅํด์ ์๊ฐํด ๋ณด์. ์๋ฅผ ๋ค์ด์ ๋ง์ ์์คํ
์์์ ์ฌ์ค์ธ, ํ๋ก๊ทธ๋จ์ ์ฃผ์ ๊ณต๊ฐ์ ์ ํ์ผ๋ก ๋ฐฐ์ด๋๊ณ , ํ๋ก๊ทธ๋จ์ ์คํ
์ ์์์ ์๋๋ก ๋์ด ๋๋ค๊ณ ๊ทธ๋ฆฌ๊ณ Heap์์ญ์ ๋ฐ์์ ์๋ก ๋์ด๋๋ค๋ ์ฌ์ค์ ์ฃผ๋ชฉํด ๋ณด์. ๊ทธ๋ฆผ์ผ๋ก ํํ๋๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ชจ์ต์ด ๋๋ค.
์ด๋ฐ ๋ฐฉ์์ผ๋ก ๊ตฌ์ฑ๋ ํ๋ก๊ทธ๋จ์ ์์คํ
์์ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๋น๊ต๋ฅผ ํ ์ ์์ง ์์๊น?
ํจ์์์ ์ด๋ฌํ ์๊ฐ์ ์ฐธ ์๋ฏธ๋กญ๋ค. onHeapํจ์๋ด์์ onTheStack๋ ์ง์ญ ๋ณ์(local variable)์ด๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๊ทธ๊ฒ์ ์คํ์ ์์นํ ๊ฒ์ด๊ณ , onHeap๊ฐ ๋ถ๋ฆด๋ onHeap์ ์คํ
ํ๋ ์์ ์๋ง ํ๋ก๊ทธ๋จ ์คํ
์ ๊ฐ์ฅ ์์ชฝ์ ๋ฐฐ์น ๋ ๊ฒ์ด๋ค. ์คํ์ ๋ฐ์ผ๋ก ์ฆ๊ฐํ๋ ๊ตฌ์กฐ์ด๊ธฐ์, onTheStack๋ ๋ฐฉ๋์ ์ด๋ ํ stack-based ๋ณ์๋ ๊ฐ์ฒด์ ๋นํ์ฌ ๋ ๋ฎ์ ์์น์ ๋ฉ๋ชจ๋ฆฌ์ ์์นํ๊ณ ์์ ๊ฒ์ด๋ค. ๋ง์ฝ address ์ธ์๊ฐ onTheStack์ ์์น๋ณด๋ค ๋ ์๋ค๋ฉด ์คํ์์ ์์์ ์๋ ๊ฒ์ด๊ณ , ์ด๋ heap์์ ์์นํ๋ ๊ฒ์ด ๋๋ ๊ฒ์ด๋ค.
~cpp
// heap์ ๋ํ ์ฌ๋ถ๊ฐ ์ ํํ์ง ์์ ์ ๊ฒ ๋ฐฉ๋ฒ
bool onHeap(const void *address)
{
char onTheStack; // ์ง์ญ ์คํ ๋ณ์(local stack variable)
return address < &onTheStack; // ์ฃผ์ ๋น๊ต
}
์ด๋ฌํ ๊ตฌ์กฐ๋ ์ณ๋ค. ํ์ง๋ง ์์ง ์ถฉ๋ถํ ์๊ฐํ์ง ์์ ๊ฒ์ด ์๋๋ฐ, ๊ทธ๊ฒ์ ๊ฐ์ฒด๊ฐ ์์นํ ์ ์๋ ์ธ๊ฐ์ง์ ์์น๋ฅผ ๊ฐ์ํ์ง ์์ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ์ด๋ค. ์ง์ญ(local) ๋ณ์,๊ฐ์ฒด(variable, object)๋, Heap์์ญ ์์ ๊ฐ์ฒด๋ ๊ฐ์ํด์ง๋ง ๋นผ๋จน์ ํ๋์ ์์ญ ๋ฐ๋ก ์ ์ (static)๊ฐ์ฒด์ ์์น ์์ญ์ด๋ค.
์ด๋ค์ ์์น๋ ์ ๋ถ ์ํ๋๋ ์์คํ
์ ์์กด์ ์ด๋ค. ํ์ง๋ง ๋ง์ ์์คํ
์ด stack์ heap์ด ์๋ก๋ฅผ ํฅํด ์ฆ๊ฐ ํ๋๋ก ๊ตฌ์ฑ๋์ด ์์ผ๋ฉฐ, ๊ฐ์ฅ ์ตํ๋จ์ static์ฌ์ญ์ด ์๋ฆฌ ์ก๋ ๊ตฌ์ฑ์ผ๋ก ๋์ด ์๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์์ ์ธ๊ธํ ๊ทธ๋ฆผ์์ ํ๊ฐ์ง๋ฅผ ์ถ๊ฐํ๋ฉด ์ง์ง ๋ฉ๋ชจ๋ฆฌ์ ๊ตฌ์ฑ์ด ๋๋ค. ๋ค์๊ณผ ๊ฐ์ด ๋ง์ด๋ค.:
๊ฐ์๊ธฐ ์ด์ ์์ ์์ฑํ onHeapํจ์๊ฐ ์ด๋ ํ ์์คํ
์์๋ ์ ํํ ์ํ์ ๋ชปํ ๊ฒ์ด ๋ช
๋ฐฑํด ์ง๋ค.:heap ๊ฐ์ฒด์ ์ ์ (static) ๊ฐ์ฒด๋ฅผ ๊ตฌ๋ณํ์ง๋ฅผ ๋ชปํ๋ค. ์์ ์์ ๋ณด๋ฉด
์ด์ heap ๊ฐ์ฒด์ stack ๊ฐ์ฒด๋ฅผ ํ๋ณํ๋ ๋ฐฉ๋ฒ์ ํผ๋์ด ์ฌ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ๋ฐฉ๋ฒ์ ์ด์์ฑ์๋ ์ญ์๋ ๋ฌธ์ ๊ฐ ์๋ค. ๊ทธ๋์ ๊ฒฐ๊ตญ compare-the-addresses ๋ฐฉ๋ฒ์ ์ ๋ขฐํ ์ ์๋ ๋ฐฉ๋ฒ์ด ๋๋ค.
~cpp
void allocateSomeObjects()
{
char *pc = new char; // heap ๊ฐ์ฒด: onHeap(pc)
// ์ด๊ฒ์ true๋ฅผ ๋ฐํ
char c; // ์คํ(=:์ง์ญ) ๊ฐ์ฒด object: onHeap(&c)
// ์ด ์ฃผ์๋ false ๋ฅผ ๋ฐํ
static char sc; // ์ ์ (static) ๊ฐ์ฒด: onHeap(&sc)
// ์ด ์ฃผ์๋ true ๋ฅผ ๋ฐํ
...
}
์ฌ๋ด์ด๋ผ๋ฉด, ์ด๋ฌํ ๋ฐฉ๋ฒ์ ๋๋ค์์ ์์คํ
์์ ์ฌ์ค์ด์ง๋ง, ๊ผญ ๊ทธ๋ ๋ค๊ณ ๋ ๋ณผ์ ์๋ค. ๊ทธ๋ฌ๋๊น ์์ ํ not portableํ๊ฒ ์๋ semi-portable์ด๋ผ๊ณ ํํ์ ํด์ผ ํ๋. ๊ทธ๋์ ์๋จธ๋ฆฌ์ ์ ์๋๋ง ์๊ฐํด ๋ณด์๊ณ ํ๊ฒ์ด๊ณ , ์ด๋ฌํ ์์คํ
์์กด์ ์ธ ์ค๊ณ๋ ์ฐจํ ๋ค๋ฅธ ์์คํ
์ ์ด์์์ ๋ฉ๋ชจ๋ฆฌ์ ํํ ๋ฐฉ๋ฒ์ด ๋ค๋ฅด๋ค๋ฉด, ์ํํธ์จ์ด ์์ฒด๋ฅผ ๋ค์ ์ค๊ณํด์ผ ํ๋ ์ํ์ฑ์ด ์๋ค. ๊ทธ๋ฅ ์๊ณ ๋ง ์์.
- DeleteMe ์ฃผ์ ๋ณํ์
~cpp
class Asset {
private:
UPNumber value;
...
};
Asset *pa = new Asset;
ํฌ์ธํฐ๊ฐ ์ง์ฐ๊ธฐ ์์ ํ๊ฐ์ ํ๋จ์, ํฌ์ธํฐ๊ฐ heap์์ ์์นํ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋๊ฐ๋ฅผ ์์๋ด๋ ๊ฒ๋ณด๋ค ์ฝ๋ค. ์๋ํ๋ฉด ์ฐ๋ฆฌ๋ operator new๋ก ์ธํด์ ๋ฐํ๋๋ ์ฃผ์์ ๋ชจ์์ผ๋ก, ์ ์์ ์ง๋ฌธ์ ๊ดํด์ ์์ ๋ผ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ฌ๊ธฐ ์์ ์ ๊ทธ๋ฐ ๋ฌธ์ ์ ๊ดํ ์ ๊ทผ ๋ฐฉ์์ด ๊ธฐ์ ๋์ด ์๋ค.
์ด๋ฌํ ๊ฒ์ ๊ฐ๋จํ๋ค. operator new๋ collection์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋ ์ฃผ์๋ฅผ ๊ธฐ๋กํ๊ณ , operator delete๋ ๊ทธ๊ฒ์ ์ง์ด๋ค. ๊ทธ๋ฆฌ๊ณ isSafeToDelete๋ collection์ ํด๋น ์ฃผ์๊ฐ ์๋์ง ์๋ ค์ฃผ๋ ์ญํ ์ ํ๋ค. ๋ง์ฝ operator new์ operator delete๊ฐ ์ ์ญ ๊ณต๊ฐ์ ์๋ค๋ฉด ์ด๊ฒ์ ๋ชจ๋ ํ์
์ ์์
์์ ์ ์ฉ ๋ ๊ฒ์ด๋ค.
~cpp
void *operator new(size_t size)
{
void *p = getMemory(size); // ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋ ์ด๋ค ํจ์๋ฅผ ํธ์ถํ๋ค.
// ๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ out-of-memory ์์ธ๋ฅผ ์ก์์ ์๋ค.
ํ ๋น๋ ์ฃผ์๋ฅผ collection์ ์ ์ฅํ๋ค.;
return p;
}
void operator delete(void *ptr)
{
releaseMemory(ptr); // ๋ฉ๋ชจ๋ฆฌ๋ฅผ freeํ๋ค.
์ด๋ฒ์ ์ง์ด ์ฃผ์๋ฅผ collection์์ ์ ๊ฑฐํ๋ค.;
}
bool isSafeToDelete(const void *address)
{
๋ฌผ์ด๋ณด๋ ์ฃผ์๊ฐ collection์์ ์กด์ฌํ๋์ง ์ฌ๋ถ๋ฅผ ๋ฐํํ๋ค.;
}
์ค์ ๋ก ์ธ๊ฐ์ง ์๊ฐ์ด ์ด๋ฌํ ๋์์ธ์ ๋งค๋ฌ๋ฆฌ์ง ๋ชปํ๊ฒ ํ๋ค. ์ฒซ๋ฒ์งธ๋ ์ ์ญ ๊ณต๊ฐ์ ์ด๋ค๊ฒ์ ์ ์ํ๋ ๊ทน๋๋ก ํผํ๋ ค๋ ๊ฒฝํฅ์ด๋ค. operator enw๋ operator delete๊ฐ์ ๋ฏธ๋ฆฌ ์ ์๋ ํจ์์ ๋ํ์ฌ ํน๋ณํ๊ฒ ๊ณ ์น๋ค๋ ๊ฒ์ ๋ ๊ทธ๋ด ๊ฒ์ด๋ค. ๋์งธ๋ก ํจ์จ์ ๊ดํ ๋ฌธ์ ์ด๋ค. ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์์ overhead๊ฐ ๋ฐ์ํ๋ค๋ ์๋ฏธ์ธ๋ฐ, ์ด๊ฒ์ ์ ์งํ๊ฒ ๋๊ฐ? ๋ง์ง๋ง์ผ๋ก ๊ฑฑ์ ๋๋ ๊ฒ์ ํ๋ฒํ์ง๋ง ์ค์ํ ๊ฒ์ผ๋ก isSafeToDelete์ด ๋ชจ๋ ์ํ์ ๊ดํ์ฌ ์ ์ฉ๋๋ ์ ์ฉํ๋ ๊ฒ์ด๋ค. ํ์ง๋ง ์ด๊ฒ์ด ๊ทผ๋ณธ์ ์ผ๋ก ๋ถ๊ฐ๋ฅํ๋ค๊ณ ๋ณด์ด๊ธฐ ๋๋ฌธ์ด๋ค. ์กฐ๊ธ๋ ์ด์ฝ ํด๋ณด์๋ฉด, ๋ค์ค ์์์ด๋, virtual base class๊ฐ ๊ฐ์ง๋ ์ฌ๋ฌ๊ฒ์ ์ฃผ์๋ค, ์ด ์ฃผ์๋ค ๋๋ฌธ์ isSafeTo Delete์๊ฒ ์ ๋ฌ๋๋ ์ฃผ์์ ๋ํ ํ์คํ ๋ณด์ฅ์ด ์๋ค. ์์ธํ ๋ด์ฉ์ Item 24, 31์ผ ์ฐธ๊ณ ํ๋ผ.
- DeleteMe)์ฃผ์ ์ ํ
๊ฐ์ ํด๋์ค๋ผ๊ณ ํด์ ๋ ์ ์๋ abstract base ๋ ์ด๊ธฐํ ๋ ์๊ฐ ์๋ค. ๋ง๋ถ์ฌ ๋งํ์๋ฉด, ์ด๊ฒ์ ์์ ๊ฐ์ ํจ์๋ฅผ ์ต์ํ ํ๋ ์ด์์ ๊ฐ์ง๊ณ ์์ด์ผ๋ง ํ๋ค. mixin("mix in")ํด๋์ค๋ ์ ์ ์๋ ๊ธฐ๋ฅ๊ณผ ์์๋๋ ์ด๋ค ํด๋์ค์๋ ์ ๋ถํฉ๋๋๋ก ์ค๊ณ๋์ด์ ธ ์๋ค. ์ด๋ฐ ํด๋์ค๋ค์ ๊ฑฐ์ ํญ์ abstract์ด๋ค. ๊ทธ๋์ ์ฌ๊ธฐ์์๋ abstract mixin base class๋ ์ฉ๋๋ก operator new๋ก ๊ฐ์ฒด์ ํ ๋น ์ฌ๋ถ๋ง ์์ ์๋ ๋ฅ๋ ฅ๋ง์ ์ ๋๋ ํด๋์ค์๊ฒ ์ ๊ณตํ๋ค.
์ด ํด๋์ค์์ list๋ฐ์ดํฐ ๊ตฌ์กฐ์ฒด๋ C++์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์๋์ด ์๋ค.(Item 35์ฐธ๊ณ ) list๊ฐ ํ๋ ์ผ์ ์์๋๋ ๊ฒ๊ณผ ๊ฐ์ด operator new์์ ๋ฐํ๋ ์ฃผ์์ ์ ์ฅ์ด๋ค. ๊ทธ๋ฆฌ๊ณ operator delete๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํ๊ณ , list๋ก ๋ถํฐ ํด๋น ์ฃผ์์ ์ํธ๋ฆฌ๋ฅผ ์ง์ด๋ค.
~cpp
class HeapTracked { // mixin class; keeps track of
public: // ptrs returned from op. new
class MissingAddress{}; // ์์ธ ํด๋์ค;์๋ ์ฐธ๊ณ
virtual ~HeapTracked() = 0;
static void *operator new(size_t size);
static void operator delete(void *ptr);
bool isOnHeap() const;
private:
typedef const void* RawAddress;
static list<RawAddress> addresses;
};
HeapTrack ์ ์ฉ์ ๊ฐ๋จํ๋ค. ์๋ํ๋ฉด, operator new์ operator delete๊ฐ ์ค์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น๊ณผ ํด์ ๋ฅผ ์ํํ๊ณ list ํด๋์ค๋ ์ฝ์
, ์ง์ฐ๊ธฐ, ๊ทธ๋ฆฌ๊ณ ๊ฒ์ ์์ง์ ํฌํจํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ ์ฌ๊ธฐ ์ด๋ฐ ๋ด์ฉ์ ์ ์ฉ์ ๊ด๋ จํ ๋ด๋ถ ์ฝ๋๋ฅผ ์ดํผ์.
์ด์ฝ๋๋ ์ฝ๊ฐ ์์ํ listํด๋์ค์ ๋ํ ๊ฒ์ด ๋ณด์ผ ๊ฒ์ด๋ค. ๋ญ, ์ด์ ๋ ํ๋ ๋ง์ด ๋์์ ๋ณ๋ก ์์์ ํ ๊ฒ ๊ฐ๋ค. STL์ด๊ณ Item 35์ ๋ชจ๋ ๊ฒ์ด ์ค๋ช
๋์ด ์๋ค. ํ์ง๋ง ์ฃผ์์ ๋ฐํ์ผ๋ก ์์ ์ ๊ดํ์ฌ ์ถฉ๋ถํ ์ค๋ช
๊ฐ๋ฅํ๋ฆฌ๋ผ๊ณ ๋ณธ๋ค.
~cpp
// static ํด๋์ค ๋ฉค๋ฒ์ ์ ์๋ ๊ท์น์ด๋ค.
list<RawAddress> HeapTracked::addresses;
// HeapTracked์ ํ๊ดด์๋ ๊ฐ์ ํด๋์ค์ ์์ ๊ฐ์ ํจ์์ด๋ค. (E14์ฐธ๊ณ )
// ๊ทธ๋์ ์ด ํ๊ดด์๊ฐ ๊ตฌํ๋์ด์ผ ๋งํ๋ค.
HeapTracked::~HeapTracked() {}
void * HeapTracked::operator new(size_t size)
{
void *memPtr = ::operator new(size); // ๋ฉ๋ชจ๋ฆฌ ํ ๋น
addresses.push_front(memPtr); // ํด๋น ์ฃผ์๋ฅผ list์ ์์ชฝ์ ์ ์ฅ
return memPtr;
}
void HeapTracked::operator delete(void *ptr)
{
// "iterator"๋ฅผ ์ป์ด์ list์์ ๊ฒ์ํ๋ ๋ถ๋ถ Item 35์ฐธ๊ณ
list<RawAddress>::iterator it = find(addresses.begin(), addresses.end(), ptr);
if (it != addresses.end()) { // ์ง์ธ ์ฃผ์๋ฅผ ์ฐพ์์
addresses.erase(it); // ํด๋น ์ํธ๋ฆฌ๋ฅผ ์ง์ฐ๊ณ
::operator delete(ptr); // ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํ๊ณ
} else { // ํ์ง๋ง
throw MissingAddress(); // ptr์ ํ ๋น์ด ์๋์๋ค๋ฉด ์์ธ๋ฅผ ๋์ง๋ค.
}
}
bool HeapTracked::isOnHeap() const
{
// *this๋ก ํ ๋น๋ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์์์ ์ ์ป๋ ๊ณผ์ ;์์ธํ๊ฑด ๋ฐ์ ๋ณธ๋ฌธ
const void *rawAddress = dynamic_cast<const void*>(this);
// ์ฃผ์ list์์ pointer๋ฅผ ์ฐพ๊ณ operator new์ ์ํด ๋ฐํ๋๋ค.
list<RawAddress>::iterator it = find(addresses.begin(), addresses.end(), rawAddress);
return it != addresses.end(); // return whether it was
} // found
๋ฉค๋ฒ ๋ฉ์๋ isOnHeap์ ์กด์ฌํ๋ ์ด ๊ตฌ๋ฌธ์ด ๋ค์ ์๋ฌธ์ด ๋ค๊ฒ์ด๋ค.
( DeleteMe ๋ชจํธ )
์์์ isSafeToDelete๋ฅผ ๊ตฌํํ ๋ ๋ค์ค ์์์ด๋ ๊ฐ์ ๊ธฐ์ด ํจ์์ผ๋ก ์ฌ๋ฌ๊ฐ์ ์ฃผ์๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด๊ฐ ์ ์ญ์ ํด๋น ํจ์๋ฅผ ๋ณต์กํ๊ฒ ํ ๊ฒ์ด๋ผ๊ณ ์ธ๊ธํ๋ค. ๊ทธ๋ฐ ๋ฌธ์ ๋ isOnHeap์์ ์ญ์ ๋ง์ฐฌ๊ฐ์ง์ด๋ค. ํ์ง๋ง isOnHeap๋ ์ค์ง HeapTracked๊ฐ์ฒด์ ์ ์ฉ ์ํจ ๊ฒ์ด๊ธฐ ๋๋ฌธ์, dynamic_cast operatror๋ฅผ ํ์ฉ์ผ๋ก ์์ ๋ฌธ์ ๋ฅผ ์ ๊ฑฐํ๋ค. ๊ฐ๋จํ ํฌ์ธํฐ๋ฅผ dynamic_cast ํ๋ ๊ฒ์ (ํน์ const void* or volatile void* or ์๋ง๋ ๊ฒ์ผ๋ก ๋ง์ถ์ด์) ๊ฐ์ฒด์ ๊ฐ์ฅ ์์ชฝ ํฌ์ธํฐ, ์ฆ, ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ฅ ์์ชฝ์ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ๋ฅผ ์๋ฏธํ๋ค. ๊ทธ๋ ์ง๋ง dynamic_cast๋ ๊ฐ์ํจ์๋ฅผ ํ๋ ์ด์ ๊ฐ์ง๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ์ ํํด์๋ง ํ์ฉ ๋๋ค. isSafeToDeleteํจ์๋ ๋ชจ๋ ํฌ์ธํฐ์ ๊ดํด์ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ dynamic_cast๊ฐ ์๋ฌด๋ฐ ์์ฉ์ด ์๋ค. isOnHeap๋ ์กฐ๊ธ๋ ์ ํ์ ํญ์ด ์์ด์ this๋ฅผ const void*๋ก dynamic_castํ๋ ๊ฒ์ ์ฐ๋ฆฌ์๊ฒ ํ์ฌ ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ ์์์ ์ใ ฃ ํฌ์ธํฐ๋ฅผ ์ฃผ๊ฒ ๋๋ค. ๊ทธ ํฌ์ธํฐ๋ HeapTracked::operator new๊ฐ ๋ฐ๋์ ๋ฐํํด์ผ๋ง ํ๋ ๊ฒ์ผ๋ก HeapTrack::operator new์ ์ฒ์ ๋ถ๋ถ์ ์๋ค. ๋น์ ์ ์ปดํ์ผ๋ฌ๊ฐ dynamix_cast๋ฅผ ์ง์ํ๋ฉด ์ด๋ฌํ ๊ธฐ์ ์ ์ด์์ฑ์ด ๋๋ค.
~cpp const void *rawAddress = dynamic_cast<const void*>(this);
์์์ isSafeToDelete๋ฅผ ๊ตฌํํ ๋ ๋ค์ค ์์์ด๋ ๊ฐ์ ๊ธฐ์ด ํจ์์ผ๋ก ์ฌ๋ฌ๊ฐ์ ์ฃผ์๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด๊ฐ ์ ์ญ์ ํด๋น ํจ์๋ฅผ ๋ณต์กํ๊ฒ ํ ๊ฒ์ด๋ผ๊ณ ์ธ๊ธํ๋ค. ๊ทธ๋ฐ ๋ฌธ์ ๋ isOnHeap์์ ์ญ์ ๋ง์ฐฌ๊ฐ์ง์ด๋ค. ํ์ง๋ง isOnHeap๋ ์ค์ง HeapTracked๊ฐ์ฒด์ ์ ์ฉ ์ํจ ๊ฒ์ด๊ธฐ ๋๋ฌธ์, dynamic_cast operatror๋ฅผ ํ์ฉ์ผ๋ก ์์ ๋ฌธ์ ๋ฅผ ์ ๊ฑฐํ๋ค. ๊ฐ๋จํ ํฌ์ธํฐ๋ฅผ dynamic_cast ํ๋ ๊ฒ์ (ํน์ const void* or volatile void* or ์๋ง๋ ๊ฒ์ผ๋ก ๋ง์ถ์ด์) ๊ฐ์ฒด์ ๊ฐ์ฅ ์์ชฝ ํฌ์ธํฐ, ์ฆ, ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ฅ ์์ชฝ์ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ๋ฅผ ์๋ฏธํ๋ค. ๊ทธ๋ ์ง๋ง dynamic_cast๋ ๊ฐ์ํจ์๋ฅผ ํ๋ ์ด์ ๊ฐ์ง๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ์ ํํด์๋ง ํ์ฉ ๋๋ค. isSafeToDeleteํจ์๋ ๋ชจ๋ ํฌ์ธํฐ์ ๊ดํด์ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ dynamic_cast๊ฐ ์๋ฌด๋ฐ ์์ฉ์ด ์๋ค. isOnHeap๋ ์กฐ๊ธ๋ ์ ํ์ ํญ์ด ์์ด์ this๋ฅผ const void*๋ก dynamic_castํ๋ ๊ฒ์ ์ฐ๋ฆฌ์๊ฒ ํ์ฌ ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ ์์์ ์ใ ฃ ํฌ์ธํฐ๋ฅผ ์ฃผ๊ฒ ๋๋ค. ๊ทธ ํฌ์ธํฐ๋ HeapTracked::operator new๊ฐ ๋ฐ๋์ ๋ฐํํด์ผ๋ง ํ๋ ๊ฒ์ผ๋ก HeapTrack::operator new์ ์ฒ์ ๋ถ๋ถ์ ์๋ค. ๋น์ ์ ์ปดํ์ผ๋ฌ๊ฐ dynamix_cast๋ฅผ ์ง์ํ๋ฉด ์ด๋ฌํ ๊ธฐ์ ์ ์ด์์ฑ์ด ๋๋ค.
์ด๋ฌํ ํด๋์ค๊ฐ ์ฃผ์ด์ง๊ณ , BASIC ํ๋ก๊ทธ๋๋จธ๋ ์ด์ heap ์ ํ ๋นํ๋ ๊ฒ์ ์ถ์ ํ ์ ์๋ ๋ฅ๋ ฅ์ ํด๋์ค์๊ฒ ๋ถ์ฌ ํ ์ ์๋ค. ์ถ์ ์ ์ํ๋ ํด๋์ค๋ ๋ฐ๋์ HeapTracked๋ฅผ ์์ํ๋๋ก ๋ง๋ ๋ค. ์๋ฅผ๋ค์ด์ ์ฐ๋ฆฌ๊ฐ Asset๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ๋ ํด๋น ๊ฐ์ฒด๊ฐ heap-base ๊ฐ์ฒด์ธ์ง ์๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด
์ด์ ์ฐ๋ฆฌ๋ Asset* ํฌ์ธํฐ์ ๊ดํด์ ๊ฐ์ฒด์ ์ํ๋ฅผ ๋ฌผ์ด ๋ณผ์ ์๋ค.
์ด mixin ๊ฐ์ฒด์ ๋จ์ ์ด๋ผ๋ฉด int๋ char๋ฐ์์ built-in ํ์๋ ์จ๋จน์ง๋ฅผ ๋ชปํ๋ ๊ฒ์ด๋ค. ์ด๊ฒ๋ค์ ์์์ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
~cpp
class Asset: public HeapTracked {
private:
UPNumber value;
...
};
~cpp
void inventoryAsset(const Asset *ap)
{
if (ap->isOnHeap()) {
ap ๋ heap-based asset ์ด๋ค.
}
else {
ap ๋ non-heap-based asset ์ด๋ค.
}
}
1.3.3. Prohibiting Heap-Based Objects : Heap์์ญ์ ๊ฐ์ฒด ์ฌ๋ฆฌ๊ธฐ ๋ง๊ธฐ ¶
๊ธฐ๋๊ธด ์ฌ์ ์ด๋ค. ์ด์ ๊ธ์ ๋ง๋ฐ์ง์ธ ์ฃผ์ ๋ก ์๋ค. ์ฌํํ ๊ฒ๊ณผ ๋ฐ๋๋ก Heap์์ญ์ ๊ฐ์ฒด๋ฅผ ์ฌ๋ฆฌ๋ใณ์ ๋ง์๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น? ์ด๋ฒ์๋ ์ด๋ฐ ๋ฐ๋์ ๊ฒฝ์ฐ์ ๊ดํด์ ์๊ฐํด ๋ณธ๋ค.
๊ณง ๋ฐ๋ก ์์ ๋ฅผ ๋ณด์.
ํด๋์ด์ธํธ์์ ๋ฐ์ํ๋ ๊ฒ์ ๊ดํด ๊ฐ์ ํ์.
26์ฅ ๋ถํฐ ๊พธ์คํ ์ ๋ด์๋ค๋ฉด ๋ณด๋ ์๊ฐ ์ดํด๊ฐ๋ ์์ ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์๋ฌธ๊น์ง ์ ๊ธฐ๋๋ค. operator new[]๋ ์ด๋ ์๋๊ฐ? ์ฆ, heap ์์ญ์ ๋ฐฐ์ด ์ ์ธ๊น์ง ๋ง๊ธฐ์ํด์๋ operator new[]๊น์ง ์ฌ์ญ(private)์ธ์๋ก ์ ์ธํด ์ฃผ๋ฉด ๋๋ค. (์ฃผ:๋ถ๋ช
ํ ๋ค๋ฅธ ์ฃผ์ ์ธ๋ฐ ์ง๊ฒน๋ค. ๋๋ฌด ๊ฐ์ ๊ฒ๋ง ๋ฐ๋ณตํ๋ ๋๋์ด ๋ ๋ค.)
~cpp
class UPNumber {
private:
static void *operator new(size_t size); // ์ ์ด๋ ๊ฒ operator new๋ฅผ
// ์ฌ์ญ(private)์ธ์๋ก ๋ง๋ค์ด ๋ฒ๋ฆฐ๋ค.
static void operator delete(void *ptr); // operator delete ์ญ์ ๋ง์ฐฌ๊ฐ์ง์ด๋ค.
...
};
~cpp
UPNumber n1; // ๋ง๋ค.
static UPNumber n2; // ์ด์ ์๋ค.
UPNumber *p = new UPNumber; // ์ฌ์ญ(private)์ธ์์ธ opreator new๊ฐ ๋ถ๋ ค์
// ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
ํฅ๋ฏธ๋กญ๊ฒ operator new์ ์ฌ์ญ(private)์ธ์๋ก์ ์ ์ธ์ UPNumber๊ฐ์ฒด๋ฅผ ์์ํ ๊ฐ์ฒด์์๋ ๊ฐ์ ๋ฅ๋ ฅ์ ๋ฐํํ๋ค๋ ์ ์ด๋ค. ๋ค์์ ์์ ๋ฅผ ๋ณด์.
๋ง์ง๋ง new๋ฅผ ์ด ๋ถ๋ถ์์๋ NonNegativeUPNumber๋ฅผ new๋ก ์์ฑํ ๋ ๋ถ๋ชจ์ธ UPNumber๋ถ๋ถ์ ์์ฑํ ๋ private๋ก ์ ์ฝ์ด ๋ฐ์๋์ด์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๋ค.
~cpp
class UPNumber { ... }; // ์์ ๊ฐ์ ์ฝ๋
class NonNegativeUPNumber: // ์ด ํด๋์ค์์๋ operator new์๋ํ
public UPNumber { // ์ ์ธ์ด ์๋ค.
...
};
NonNegativeUPNumber n1; // ์ด์ ์๋ค.
static NonNegativeUPNumber n2; // ์ญ์ ์ด์ ์๋ค.
NonNegativeUPNumber *p = // ์ฌ์ญ(private)์ธ์์ธ opreator new๊ฐ ๋ถ๋ ค์
new NonNegativeUPNumber; // ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
๋ฐ๋ฉด์ ์์ ์ฝ๋๊ฐ ๊ทธ๋๋ก๋ผ๋ฉด, ๋ค์๊ณผ ๊ฐ์ ์ฝ๋ ๊ฐ์ด has-a๊ด๊ณ์ ๊ฒฝ์ฐ์๋ ๊ฐ๋ฅํ๋ค.
๋ท๋ถ๋ถ์ ์์ ํ๋ heap์์ญ์ ์ฃผ์ ๊ธฐ๋ฐ์ ๊ฒ์ถ๊ณผ ์ด์์ฑ์ ๋ํ ๋
ผ์์ด๋ค.
~cpp
class Asset {
public:
Asset(int initValue);
...
private:
UPNumber value;
};
Asset *pa = new Asset(100); // ๋ง๋ค.
// ์ด๊ฒฝ์ฐ Asset::operator new ๋
// ::operator new๋ ๋ถ๋ฆฌ์ง๋ง
// UPNumber::operator new๋ ๋ถ๋ฆฌ์ง ์์ผ๋ฏ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋ค.
1.4. Item 28: Smart pointers ¶
- Item 28: ๋๋ํ ํฌ์ธํฐ:์ค๋งํธ ํฌ์ธํฐ
C++์ built-in ํฌ์ธํฐ๋ก์(๋ค์ ๋งํด dumb(๊ฐ์์ ๋๋ก ํด์, ์ดํ "๋๋ฏธ"๋ก ํํ) ํฌ์ธํฐ) ์ค๋งํธ ํฌ์ธํฐ ์ฌ์ฉํ๋ค. ์ด๋ด ๊ฒฝ์ฐ ์์ผ๋ก ๋ค๋ฅผ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ๋ค์ ๋ฌธ์ ๋ค์ด ๋
ผ์ ๋๋ค.
(์์ฑ์์ฃผ:dumb pointer๋ฅผ ๋ค ํฌ์ธํฐ ๋ผ๊ณ ๋ถ๋ฅด์ง ์๊ณ ๋๋ฏธ(dummy) ํฌ์ธํฐ๋ผ๊ณ ๋ถ๋ฅด๋๊ฑด ์๋ฏธ ํธ๋์ง๋ง, ๋ฅ๋ ฅ์ ์์คํ ๊ฐ์ง ํฌ์ธํฐ์ ์๋ฏธ๋ก ์ฌ์ฉํ๋ค. ํนํ Evangelion์์ ๋๋ฏธ ๋ผ๋ ํํ์ด ๊ด์ฐฎ์ ์ด๊ฐ์ด๊ธฐ์ ์ฐจ์ฉํ๋ค๋ ํ๋ฌธ์ด.. )
ํ์ฌ ๋ณต์ฌ ์์ฑ์์(copy constructor), ํ ๋น ์ฐ์ฐ์(assignment operator)๊ฐ ํน๋ณํ ์ ์ธ๋์ด ์์ง ์์ผ๋ฏ๋ก, ๋๋ค ๊ณต์ญ(public)์ธ์์ด๋ค. ๋ฌธ์ ๋ ํจ๋ถ๋ก ์ด๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ๊ฐ๋ฆฌํค๋ ๋๋ฏธ(dumb)ํฌ์ธํฐ๊ฐ ๊ฐ์ ์ง๋ฏ๋ก built-in ํ์ผ๋ก ์์ฑ๋๋ ์ค๋งํธ ํฌ์ธํฐ ๋์ด ์ฌ๋ผ์ง๋ ์์ญ์ ๋ฒ์ด๋๋ ์์ ์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ delete ํ๋ ค๊ณ ํ ์ ์๋ค. ์ด์ ๋ํ ๋ณด์์ด ํ์ํ๋ค.
(์์ฑ์์ฃผ:dumb pointer๋ฅผ ๋ค ํฌ์ธํฐ ๋ผ๊ณ ๋ถ๋ฅด์ง ์๊ณ ๋๋ฏธ(dummy) ํฌ์ธํฐ๋ผ๊ณ ๋ถ๋ฅด๋๊ฑด ์๋ฏธ ํธ๋์ง๋ง, ๋ฅ๋ ฅ์ ์์คํ ๊ฐ์ง ํฌ์ธํฐ์ ์๋ฏธ๋ก ์ฌ์ฉํ๋ค. ํนํ Evangelion์์ ๋๋ฏธ ๋ผ๋ ํํ์ด ๊ด์ฐฎ์ ์ด๊ฐ์ด๊ธฐ์ ์ฐจ์ฉํ๋ค๋ ํ๋ฌธ์ด.. )
- Construction and destruction.(์์ฑ๊ณผ ํ๊ดด)
์ค๋งํธ ํฌ์ธํฐ๋ ์๋์ผ๋ก 0 or null์ ์ด๊ธฐํ๋ก ๋ฏธ ์ด๊ธฐํ๋ก ์ธํ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ณ , ํ๊ดด์์๋ built-in ํ์ ์ ํน์ฑ์ผ๋ก ์๋์ผ๋ก ํ๊ดด ์์ผ์ค๋ค.
- Copying and assignment. (๋ณต์ฌ์ ํ ๋น)
์ค๋งํธ ํฌ์ธํฐ์์ ๊ฐ์ฅ ์ฌ๊ฐํ ์ ์ฝ ์ฌํญ์ ์ผ์ผํค๋ ๊ฒ์ด ๋ณต์ฌ์ ํ ๋น ๋ฌธ์ ์ธ๋ฐ(์ฐจํ ๋ ผ์๋๋ค.) ์ด์ ๋ํ ์ด์ ์, ์ณ๋ฐ๋ฅธ ๋ฐฉํฅ์ ์ ์๋ฅผ ํ๋ค.
- Dereferencing. (์ญ์ฐธ์กฐ)
ํด๋ผ์ด์ธํธ๋ ์ค๋งํธ ํฌ์ธํฐ๊ฐ ๊ฐ์ง ํด๋์ค๋ฅผ ์ด๋ค ๋ ์ด๋ป๊ฒ ์ฐธ์กฐ๋ฅผ ํด์ผ ํ ๊น? ์๋ฅผ๋ค์ด์ lazy fetching(Item 17์ฐธ๊ณ )๋ฅผ ์ค๋งํธ ํฌ์ธํฐ ๊ตฌํํ๋ ๊ฒ๊ณผ ๊ฐ์ด ์ฌ๋ฌ ๊ฒฝ์ฐ์ ๋ํ ๋ฌธ์ ๋ฅผ ์๊ฐํ์.
~cpp
template<class T> // ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์ํ ํ
ํ๋ฆฟ
class SmartPtr { // ํฌ์ธํฐ ๊ฐ์ฒด
public:
SmartPtr(T* realPtr = 0); // ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์ฃผ์ด์ง ๋๋ฏธ(dumb) ํฌ์ธํฐ๋ก
// ์ด๊ธฐํ ์ํค๋๋ฐ, ํ ๋น๋์ง ์์ผ๋ฉด
// ๋๋ฏธ(dumb)ํฌ์ธํฐ๋ฅผ 0(null)๋ก ์ด๊ธฐํ ์ํจ๋ค.
SmartPtr(const SmartPtr& rhs); // ์ค๋งํธ ํฌ์ธํฐ ๋ณต์ฌ ์์ฑ์
~SmartPtr(); // ์ค๋งํธ ํฌ์ธํฐ์ ํ๊ดด์
// ์ค๋งํธ ํฌ์ธํฐ์ ๊ฐ์ ํ ๋นํ๋ค.
SmartPtr& operator=(const SmartPtr& rhs);
T* operator->() const; // ์ฐธ์กฐ ํ๊ธฐ:์๋ฃ์ ์ ๊ทผํ๋๋ก ํฌ์ธํฐ๋ฅผ ์ ๊ณตํ๋ค.
T& operator*() const; // ์ฐธ์กฐ ํ๊ธฐ:๋ง์ฐฌ๊ฐ์ง
private:
T *pointee; // ํ์ฌ ์ค๋งํธ ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๊ณ ์๋ ๊ฒ
// ์ด๊ฒ์ด ์ง์ ์ ๊ทผ ๋ชปํ๋ ๋๋ฏธ(dumb) ํฌ์ธํฐ ์ด๋ค.
};
๊ทธ๋ฆฌ๊ณ , ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์์ธํ ๋ค๋ฃจ๊ธฐ์ ์์์, ์ค๋งํธ ํฌ์ธํฐ๊ฐ ์์ฑ๋๋ ํ๋์ ๊ฐ์ ์๋๋ฆฌ์ค๋ฅผ ์์ฑํ๋ค. ์ด์ ๋ ์ ์ฐจ ์ค๋งํธ ํฌ์ธํฐ์ ๊ดํ ์์ธํ ์ค๋ช
์ด ํ์ํ ๋, ์ด ๊ฐ์ ์๋๋ฆฌ์ค์์์ ๋ฐ์ํ๊ฑฐ๋, ํด๋น ๋ฌธ๋ฒ์์ ๊ฐ์ํด์ผ ํ ์์ธ๋ค์ ๋
ผํ๊ธฐ ์ํด ์๋๋ฆฌ์ค์ ์ ์ฒด ์ค๊ณ๋ฅผ ์ ์ํ๋ค.
์ค์ ๋ ์๋๋ฆฌ์ค๋ ๋ถ์ฐ ์์คํ
์, ๋ถ์ฐ DB์์, local ์ ์๋ ๊ฐ์ฒด์, remote์ ์๋ ๊ฐ์ฒด๋ฅผ ๋ค๋ฃจ๊ธฐ ์ด๋ค. ํด๋ผ์ด์ธํธ ์
์ฅ์์๋ ๋์ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ด ์ด์ํ ๋์ด ์์ด์, ํด๋น ๊ฐ์ฒด์ ํ๋ก์์ ํธ์ถ์ ์ผ๊ด์ฑ์ด ์์ ๊ฒฝ์ฐ ํ๋ก๊ทธ๋๋ฐ ํ๊ฒฝ์ด ๋ถํธํ๊ณ , ๋ช
์์ฑ์ด ๋จ์ด์ง๋ ๋ฑ ์ฌ๋ฌ ๋ถ๋ฆฌํ ์ ์ด ์๋ค. ๊ทธ๋์ ์์ ์์ชฝ์ ๊ฐ์ฒด์ ์ฌ์ฉ๋ฒ์ ๋ํ ์ผ๊ด์ฑ์ ๊ฐ์ง๊ณ ์ถ์ด ํ๋ค. ์ด๋ฅผ ํด๊ฒฐ ํ๊ธฐ ์ํด์ ์ค๋งํธ ํฌ์ธํฐ๋ก, ํด๋น ๊ฐ์ฒด๋ฅผ ๋๋ฌ์ธ์, ํ๋ก์์ ์ ์ผ๊ด๋ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ ๊ณต ๋ฐ๊ณ ์ ํ๋ค. ๋ค์์ ๊ทธ๊ฒ์ ๊ตฌํํ ์ฝ๋๋ค์ด๋ค.:
editTuple์ ๋ด๋ถ์์ ์์ ๋์ด์ง๋ tuple์ ์๋ง๋ ์๊ฒฉ(remote)์ง์ ๊ธฐ๊ณ์ ์กด์ฌํ๋ ๊ฐ์ฒด์ด๋ค. ํ์ง๋ง, editTuple์ ์ฌ์ฉํ๋ ํ๋ก๊ทธ๋๋จธ๋ ์ด๋ฌํ ์ฌํญ์ ๋ํ์ฌ ์ค๋งํธ ํฌ์ธํฐ ๋๋ฌธ์ ํน๋ณํ ์๊ดํ ํ์๊ฐ ์๋ค.
~cpp
template<class T> // ๋ถ์ฐ DB์์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ์ค๋งํธ ํฌ์ธํฐ
class DBPtr { // ํ
ํ๋ฆฟ
public:
DBPtr(T *realPtr = 0); // DB์์ DB๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋๋ฏธ ํฌ์ธํฐ๋ฅผ ๋ฐํ์๋ก
// ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์์ฑํ๋ค.
DBPtr(DataBaseID id); // DB ๊ฐ์ฒด์์ DB ID๋ฅผ ๋ฐํ์ผ๋ก ์ค๋งํธ ํฌ์ธํฐ๋ฅผ
// ์์ฑํ๋ค.
... // DB๋ฅผ ์ํ ๋ค๋ฅธ ์์
๋ค
};
class Tuple { // ๋ฐ์ดํฐ ํ์ด์ค์ tuple๋ฅผ ์ํ ํด๋์ค
public:
...
void displayEditDialog(); // tuple์ ์์ ์ ํ๊ธฐ ์ํ ์ ์ ์
// ๊ทธ๋ํฝ ์ธํฐํ์ด์ค(์์ ์ด ํ๋ฝ๋๋ ํ์์)
bool isValid() const; // *this ๋ฐํ์ ์ ํจ์ฑ ์ ๊ฒ
};
// T๊ฐ์ฒด๊ฐ ์์ ๋์ด ํด๋น log๋ฅผ ๋จ๊ธฐ๋ ์ญํ ์ ํ๋ ํด๋์ค ํ
ํ๋ฆฟ
template<class T>
class LogEntry {
public:
LogEntry(const T& objectToBeModified);
~LogEntry();
};
void editTuple(DBPtr<Tuple>& pt)
{
LogEntry<Tuple> entry(*pt); // ์์ ์ ์ํ ํด๋น log ์ํธ๋ฆฌ๋ฅผ ์์ฑํ๋ค.
// ์์ธํ ์ค๋ช
์ ์๋
// ์ ํจํ ๊ฐ์ด ์ฃผ์ด์ง๊ธฐ ๊น์ง ์์ dialog๋ฅผ ๋ฐ์ฐ๊ธฐ ์ํ ์๊ตฌ๋ฅผ ๊ณ์ํ๋ค.
do {
pt->displayEditDialog();
} while (pt->isValid() == false);
}
editTuple๋ด์ LogEntry๊ฐ์ฒด๋ฅผ ์๊ฐํด ๋ณด์. ์์ ์ ์ํ log๋ฅผ ๋จ๊ธฐ๊ธฐ์ํด์๋ displayEditDialog์ ์์๊ณผ ๋์์ ๋งค๋ฒ ๋ถ๋ฌ์ฃผ๋ฉด ๋๋๋ฐ, ๊ตฌ์ง ์ ๊ตฌ์ง ์ด๋ ๊ฒ ํ์๊น? ์ด์๊ดํ ๋ด์ฉ์ ์์ธ์ ๊ด๋ จ๋ ์ํฉ ๋๋ฌธ์ธ๋ฐ, Item 9๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋๋ค.
๋น์ ์ด ๋ณผ์ ์๋ ๊ฒ์ฒ๋ผ ์ค๋งํธ ํฌ์ธํฐ๋ ๋๋ฏธ(dumb)ํฌ์ธํฐ๋ฅผ ๊ทธ๋ฅ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ํฌ๊ฒ ์ฐจ์ด์ ์ ์์ด ๋ณด์ธ๋ค. ๊ทธ๊ฒ์ ์บก์ํ์ ๋ํ ํจ์จ์ฑ์ ๋
ผํ๋ ๊ฒ๊ณผ ๊ฐ๋ค. ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๋ ๊ทธ๋ฅ ๋๋ฏธ(dumb)ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ฒ๋ผ ์ฌ์ฉํ๋ฏ๋ก์, ์ค๋งํธ ํฌ์ธํฐ๊ฐ ์ด๋ค ์ผ์ ํํ๋์ง ํน๋ณํ ๊ด์ฌ์ ์์ ํ์๊ฐ ์๊ฒ ๋ง๋๋ ๊ฒ์ด ๊ด๊ฑด์ด๋ค.
1.4.1. Construction, Assignment and Destruction of Smart Pointers : ์ค๋งํธ ํฌ์ธํฐ์ ์์ฑ, ํ ๋น, ํ๊ดด ¶
- ์์ฑ์:Constructor ๊ด๋ จ
- ๋ณต์ฌ ์์ฑ์(copy Constructor), ํ ๋น ์ฐ์ฐ์ (assignment operator) ๊ด๋ จ
auto_ptr ํ
ํ๋ฆฟ์ ๊ดํด์ ์๊ฐํด ๋ณด์. Item 9์์ ์ค๋ช
ํ ๊ฒ๊ณผ ๊ฐ์ด auto_ptr์ heap-based ๊ฐ์ฒด๋ฅผ auto_ptr์ด ํ๊ดด ๋ ๋๊น์ง ๊ฐ๋ฆฌํค๋ ์ญํ ์ ํ๋ค. ๋ง์ฝ auto_ptr์ด ํ๊ดด๋์ด์ง๋ ๊ฒฝ์ฐ(์กด์ฌ ์ง์ญ์ ๋ฒ์ด๋ ๋) ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๋ ํ๊ดด๋์ด์ง๋ค. auto_ptr์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์๋ค.
์ด๋ ๊ฒ ๊ตฌํ๋์ด ์๋ ์ํฉ์์, ๋ง์ฝ auto_ptr์ ๋ณต์ฌ(copy)ํ๊ฑฐ๋ ํ ๋น(assign)ํ๋ฉด ์ด๋จ๊ฒ ๋ ๊น? ๋ค์๊ณผ ๊ฐ์ด ๋ง์ด๋ค.
์ด ๋(copy, assign)์ ์๋ฏธ๊ฐ, ๋ง์ฝ ๋ด๋ถ์ ๋๋ฏธ(dumb) ํฌ์ธํฐ๋ฅผ ๋ณต์ฌ ํ์๋ค๋ฉด, ํด๋น ๋๊ฐ์ auto_ptr์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ ๊ฒ์ด๋ค. ๊ทธ๋ ๋ค๋ฉด, ์ฐจํ์ auto_ptr์ด ํ๊ดด๋๋ ์์ ์์ ํ๋์ ๊ฐ์ฒด๋ฅผ ์ฐ์์ผ๋ก ๋๋ฒ ํ๊ดดํ๋ ค๊ณ ์๋ ํ ๊ฒ์ด๋ค. ์ด๊ฒ์ ์๋ชป ๋๊ฒ์ด๋ค.
~cpp
template<class T>
class auto_ptr {
public:
auto_ptr(T *ptr = 0): pointee(ptr) {}
~auto_ptr() { delete pointee; } // ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๋ฅผ ํ๊ดดํ๋ค.
...
private:
T *pointee;
};
~cpp auto_ptr<TreeNode> ptn1(new TreeNode); auto_ptr<TreeNode> ptn2 = ptn1; // ๋ณต์ฌ ์์ฑ์๋ฅผ ํธ์ถํ๋ค. ์ด๋ค ์ผ์ด ์ผ์ด๋ ๊น? auto_ptr<TreeNode> ptn3; ptn3 = ptn2; // operator=๋ฅผ ํธ์ถํ๋ค. ์ด๋ค ์ผ์ด ์ผ์ด๋ ๊น?
์ด๋ ๊ฒ ์ ๊ธฐ๋๋ ๋ฌธ์ ์ ๋์์ผ๋ก ๊ฐ๋ฆฌํค๊ณ ์๋ ๊ฐ์ฒด์ ๋ํ์ฌ ๋ณต์ฌ๋ฅผ ์ํํ๋ค์ ๊ฐ๋ฆฌํค๋๋ก ๋ง๋ค์ ์๋ค. ํ์ง๋ง ์ด๋ฐ ๊ตฌํ ์ํ๋ ์์นซ, ๋ง์ copy, assign์ ๋จ๋ฐ์์ new์ delete์ ๋ค๋์ ํธ์ถ๋ก, ์๋ ์ ํ์, "๊ฐ์ ๊ฒ์ ๊ฐ์ ๊ฒ์ ๊ฐ๋ฆฌํค๊ณ ์๋ค." ๋ผ๋ ์๋ฏธ๋ก ์ด ํ๋ก๊ทธ๋๋จธ์๊ฒ ์๋ฏธ๋ฅผ ํธ๋ ์์ผ๋ฒ๋ฆด์ ์๋ค.
์ด๋ฐ ๋ฌธ์ ๋ auto_ptr์ด ๋ง์ฝ ๋ณต์ฌ(copying)์ ํ ๋น(assignment)๋ฅผ ํ์ง ์๋๋ค๋ฉด, ๊ทผ๋ณธ์ ์ผ๋ก ์ ๊ฑฐ ๋ ์ ์๋ค. ํ์ง๋ง auto_ptr ํด๋์ค๋ฅผ ๊ฐ๋จํ ์กฐ์ํด์ ๋ฌธ์ ๋ฅผ ํผํด๋ณธ๋ค. ์์์ ์ธ๊ธํ๊ฒ๊ณผ ๊ฐ์ด ๊ฒ์ผ๋ก๋ ๋ณต์ฌ์ด์ง๋ง, ๋ด๋ถ์ ์ผ๋ก๋ ์์ ๊ถ(ownership)๋ฅผ ๋๊ธฐ๋ ์์
์ ํ๋๋ก ๊ตฌ์ฑํ๋ ๊ฒ์ด๋ค. ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
์ด๋ ๊ฒ ๋ณต์ฌ ์์ฑ์(copy constructor)๊ฐ ๋ถ๋ฆฌ๊ฑฐ๋ ํ ๋น ์ฐ์ฐ์(assignment operator)๋ฅผ ํธ์ถํ ๊ฒฝ์ฐ ์์ ๊ถ(ownership)์ ์ด์ํ๋ค. ๋ง์ฝ ์ด๋ฐ ์์
์ด ์คํจํ๋ฉด, ๊ฒฐ์ฝ ๊ฐ์ฒด๋ ์ง์์ง์๊ฐ ์๋ค. ํ์ง๋ง ์ด๋ฐ ๋ฐฉ์์ ์น๋ช
์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ๋ถ๋ฌ ์ฌ์ ์๋ค.
~cpp
template<class T>
class auto_ptr {
public:
...
auto_ptr(auto_ptr<T>& rhs); // ๋ณต์ฌ ์์ฑ์
auto_ptr<T>& operator=(auto_ptr<T>& rhs); // ํ ๋น(assignment) ์ฐ์ฐ์
...
};
template<class T>
auto_ptr<T>::auto_ptr(auto_ptr<T>& rhs)
{
pointee = rhs.pointee; // ์์ ๊ถ(ownership)์ ์ด์ํ๋ ์์
rhs.pointee = 0; // rhs์ ์์ ๊ถ(ownership)์ ๋ฐํํ๋ค.
}
template<class T>
auto_ptr<T>& auto_ptr<T>::operator=(auto_ptr<T>& rhs)
{
if (this == &rhs) // ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋๊ฑด 1=1 ๊ฐ์ ๊ฒฝ์ฐ๋ฐ์
// ์๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์๋ฌด๋ฐ ์์
์ ํ์ง ์๋๋ค.
delete pointee; // ํด๋น ๋๋ฏธ(dumb) ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๋ฅผ
// ์ญ์ ํ๋ค.
pointee = rhs.pointee; // ์์ ๊ถ(ownership)์ ์ด์ํ๋ค.
rhs.pointee = 0; // rhs์ ์์ ๊ถ(ownership)์ ๋ฐํํ๋ค.
return *this;
}
๊ฐ์ฒด์ ์์ ๊ถ(ownership)์ด auto_ptr์ ๋ณต์ฌ ์์ฑ์์ ์ํ์ฌ ์ด์๋๋ฏ๋ก, ๋ง์ฝ auto_ptr์ ๊ฐ์ ์ํ ์ ๋ฌ(by value)๋ก ๋๊ฒจ ๋ฒ๋ฆฌ๋ฉด ๋์์ฌ์ ์๋ ๊ฐ์ ๊ฑด๋๋ ๊ผด์ด ๋๋ค.
printTreeNode์๊ฒ auto_ptr<TreeNode> ํ์ธ ptn์ด ๊ฐ์ ์ํ ์ ๋ฌ(by-value)๋ก ์ ๋ฌ ๋๋ฏ๋ก, printTreeNode๊ฐ ์ํ๋๊ธฐ์ ์ ์์ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ณ ๊ฑฐ๊ธฐ์ ptn์ด ๋ณต์ ๋๋ค. ์ด๋ ๋ถ๋ฆฌ๋ ๋ณต์ฌ ์์ฑ์(copy constructor)๋ ๊ฐ์ง๊ณ ์๋ ๋๋ฏธ(dumb) ํฌ์ธํฐ๋ฅผ ๋๊ธฐ๋ ์์ ๊ถ(ownership) ์ด์ ์์
์ ํ๊ฒ๋๊ณ , printerTreeNode๊ฐ ๋ง์น๋ค์ ํด๋น ๊ฐ์ฒด๋ ์ญ์ ๋๊ณ , ptn์ 0(null)๋ก ์ด๊ธฐํ ๋์ด ์ง๋ค. auto_ptr์ ์์ด ๋ฒ๋ฆฐ ๊ฒ์ด๋ค.
~cpp
// ๊ฐ์ ์ํ ์ ๋ฌ(by value)๋ก auto_ptr์ ๋๊ธด๋ค.
void printTreeNode(ostream& s, auto_ptr<TreeNode> p)
{ s << *p; }
int main()
{
auto_ptr<TreeNode> ptn(new TreeNode);
...
printTreeNode(cout, ptn); // ๊ฐ์ ์ํ ์ ๋ฌ(pass auto_ptr by value)
...
}
๊ทธ๋ ๋ค๋ฉด ๊ฐ์ผ๋ก์ ์ ๋ฌ์ด ์๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด๋ผ๋ฉด? ์์ ์ฐธ์กฐ ์ ๋ฌ(Pass-by-reference-to-const)๋ก ํ๋ค๋ฉด ๋์ง ์์๊น? ๊ตฌํ ์ฝ๋๋ฅผ ๋ณด์
ํด๋น ์์ ์ ์์ ์ฐธ์กฐ ์ ๋ฌ(Pass-by-reference-to-const)์ ์ธ์ p๋ ๊ฐ์ฒด๊ฐ ์๋๋ค. ๊ทธ๊ฒ์ ๊ทธ๋ฅ ์ฐธ์กฐ์ผ ๋ฟ์ด๋ค. ๊ทธ๋์ ์๋ฌด๋ฐ ์์ฑ์๊ฐ ๋ถ๋ฆฌ์ง ์๋๋ค. ๊ทธ๋์ ์์ ๊ถ(ownership)์ ๋๊ธด ์ธ์์ ๊ทธ๋๋ก ๋จ์ ์์ผ๋ฉฐ ๊ฐ์ผ๋ก์ ์ ๋ฌ(by-value)์์ ์ผ์ด๋๋ ๋ฌธ์ ๋ฅผ ๋ง์์ ์๋ค.
~cpp
// ์ง๊ด์ ์ธ ์์ ์ด๋ค. auto_ptr<TreeNode>๋ฅผ ์์ ์ฐธ์กฐ ์ ๋ฌ(Pass-by-reference-to-const)ํ์๋ค.
void printTreeNode(ostream& s, const auto_ptr<TreeNode>& p)
{ s << *p; }
์์ ๊ถ(ownership)์ ์ ๋ฌํ๋ ๊ฐ๋
์ ๋ค๋ฃฌ๊ฑด ์ฐธ ํฅ๋ฏธ๋กญ์ง๋ง, ์ฌ์ฉ์๋ ๊ฒฐ์ฝ ์ฌ๋ฏธ์์ง ์๋ค๊ณ ์๊ฐ๋๋ค. ์ด๋ ๋ณต์ฌ(copy)๋ ํ ๋น(assign)์ ์๋์ ์๋ฏธ๋ฅผ ์์ ์ํค๋ ๋ฉด์ด๋ผ์, ํ๋ก๊ทธ๋๋จธ๋ ํผ๋์ค๋ฌ์ธ ๋ฟ์ด๋ค. ๊ฐ๋ค๊ฐ ํจ์๋ค์ด ๋ชจ๋ ์์ ์ฐธ์กฐ ์ ๋ฌ(Pass-by-reference-to-const)๋ก ์์ฑ๋๋ค๋ ๋ฒ๋ ์๋ค. ์ฆ, ์ฐ์ง ๋ง๋ผ๋ ์๋ฆฌ๋ค.
auto_ptr์ ๊ด๋ จํ ๋ด์ฉ์ ์ด ์ฑ
์ ํ๋ฐ์ ๋ค๋ฃจ์ด ์๋ค.(์ ํํ 291-294์ชฝ) ์ด๋ฒ์ฅ ์ฌ๊ธฐ์ ๊ตฌํ๋ ์ฝ๋๋ค์ด auto_ptr์ 100% ์ฝ๋๊ฐ ์๋๋ฏ๋ก, STL์ auto_ptr์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๊ผญ ๋ณด๊ธฐ๋ฅผ ๋ฐ๋๋ค. ์์ ์ฌ์ค ๋ฐ๋ง๊ณ ๋ง์ด๋ค.
- ํ๊ดด์(destuctor)๊ด๋ จ
~cpp
template<class T>
SmartPtr<T>::~SmartPtr()
{
if (*this ๊ฐ ๊ฐ์ง๊ณ ์๋ *pointee) {
delete pointee;
}
}
- ๋งบ์๋ง:์ฐจํ์ ์ค๋งํธ ํฌ์ธํฐ๋ Reference Counting(Item 29)์ ๊ตฌํํ๋๋ฐ ์ ์ฉ ๋๋ค. ๊ทธ๋ ๋ค์ ์ค๋งํธ ํฌ์ธํฐ์ ๋ํ ์ฐ์์ ๋ํ์ฌ ๋๊ปด ๋ณด๊ธฐ๋ฅผ ๋ฐ๋๋ค.
1.4.2. Implementing the Dereferencing Operators : ์ญ์ฐธ์กฐ(Dereferencing) ์ฐ์ฐ์์ ์ ์ฉ ¶
~cpp
template<class T>
T& SmartPtr<T>::operator*() const
{
"์ค๋งํธ ํฌ์ธํฐ"(๋๋ํ ํฌ์ธํฐ ๊ธฐ๋ฅ?)๋ฅผ ์ํํ๋ค.;
return *pointee;
}
์ด ํจ์์ ๋ฐํ ํ์ ์ฐธ์กฐ(reference)์ด๋ค. ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉด ์ด๋ป๊ฒ ๋๋๊ฐ? ๋๋ฆฌ๋ ์๋๊ฒ์ด๋ค. ๊ฐ์ฒด์ ๋ฐํ์ ๊ฐ์ฒด๊ฐ ๋ณต์ฌ๋ก ์ ๋ฌ์์ ์์ฑ, ์ญ์ ์์์ ๋นํจ์จ์ ๋ฌผ๋ก , Item 13์ ์ ์๋๋ slicing์ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ์๋ค. ๋ Item 13์์๋ ๊ณ์ ๋ค๋ฃฌ ๊ฐ์ ํจ์๋ฅผ ํธ์ถํ ๋ ์ญ์ ๊ฐ์ฒด๋ฅผ ํตํ ๋ฐํ์ ๋ฌธ์ ๋ฅผ ๋ฐ์์ํจ๋ค. Reference๋ก ์ ๋ฌํด๋ผ, ์ด๊ฒ์ ํจ์จ์ฑ์ ๊ดํด์๋ ์ด๋ฏธ ๋ค๋ฃจ์๊ธฐ์ ๋ ๋งํ์ง ์๋๋ค.
ํ๊ฐ์ง ๋ ์๊ฐํด ๋ณด๋ฉด ๋๋ฏธ(dumb) ํฌ์ธํฐ์ธ pointee๊ฐ null๊ฐ์ธ ๊ฒฝ์ฐ์ ์ฐธ์กฐ๋ ์ด๋ป๊ฒ ๋ ๊น? ์์ฌํด๋ผ. ์ด์ํฉ์ C++์ ์ค๊ณ ๋จ๊ณ์์ ์ด๋ฏธ ์ํ์ง ์๋ ๊ฒ์ด๋ผ ๊ฐ์ ํ๊ณ , ์์ธ๋ฅผ ๋ฐ์ ์ํค๋๋ก ์กฐ์นํด ๋์๋ค. abort(์ค์ง)๋ฅผ ์ํ๋๊ฐ? ๊ทธ๋ ๊ฒ ๋๋ค.
์ญ์ฐธ์กฐ(dereference)์ ๋ค๋ฅธ ์ฐ์ฐ์์ธ operator->๋ฅผ ์๊ฐํด ๋ณด์. operator*๊ณผ ๋น์ทํ ์ญํ ์ด์ง๋ง ์ด๊ฒ์ ๋๋ฏธ(dumb) ํฌ์ธํฐ ๊ทธ ์์ฒด๋ฅผ ๋ฐํํ๋ค. ์์ ์์ ์ค, operator->๊ฐ ๋ฑ์ฅํ ์๊ฒฉ DB ์ ๊ทผ์ ๊ดํ ์์ ๋ก ์๊ฐํด ๋ณธ๋ค.
๊ทธ๋ฌ๋๊น. ๋ถ๋ถ์ ๊ตฌ๋ฌธ์ด
์ปดํ์ผ์ ์ด๋ฐ ์๋ฏธ๋ก ๊ต์ฒด๋๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.
์๊ฐํด ๋ณด๋ฉด operator->์ ์๋ฏธ๋ ๋๊ฐ์ง๋ฅผ ๊ฐ์ง์ ์๋ค. ์ค๋งํธ ํฌ์ธํฐ ๊ฐ์ฒด ์์ฒด์ ํฌ์ธํฐ๋ฅผ ์ง์นญํ๋ ๋ค์ ๋ณดํต์ ์๋ฏธ๋ก์ ํฌ์ธํฐ์, ์ค๋งํธ ํฌ์ธํฐ ๊ฐ์ฒด๊ฐ ๊ฐ์ง๊ณ ์๋ ๋๋ฏธ(dumb) ํฌ์ธํฐ๊ฐ ๊ทธ๊ฒ์ธ๋ฐ, ์ค๋งํธ ํฌ์ธํฐ์ ์ฌ์ฉ ์ฉ๋์ ์ฌ์ฉ์๋ ๋๋ฏธ(dumb)ํฌ์ธํฐ๋ฅผ ๋ฐํ ๋ฐ๊ธฐ๋ฅผ ์ํ ๊ฒ์ด๋ค. ๊ทธ๋์ operator->๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์๋ค.
ํด๋นํจ์๋ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฌ๋๊ณ , ๋๋ฏธ(dumb) ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด์ ๊ฐ์ ํจ์๋ค๋ ์ฌ๋ฐ๋ฅด๊ฒ ๋งํฌ ๋ ๊ฒ์ด๋ค.
~cpp
{
LogEntry<Tuple> entry(*pt);
do {
pt->displayEditDialog();
} while (pt->isValid() == false);
}
~cpp pt->displayEditDialog();
~cpp (pt.operator->())->displayEditDialog();
~cpp
template<class T>
T* SmartPtr<T>::operator->() const
{
"์ค๋งํธ ํฌ์ธํฐ"(๋๋ํ ํฌ์ธํฐ ๊ธฐ๋ฅ?)๋ฅผ ์ํํ๋ค.;
return pointee;
}
๋ง์ ์ดํ๋ฆฌ ์ผ์ด์
์์ ์ค๋งํธ ํฌ์ธํฐ์ ๊ฐ์ ๊ธฐ๋ฒ์ ์ฌ์ฉํ๋ฏ๋ก ์ ์์ ๋๊ธฐ๋ฅผ ๋ฐ๋๋ค. ํนํ๋ ๊ณ์ ํ๋ณดํด์ ์ง๊ฒน๊ฒ ์ง๋ง Reference count์ชฝ์์ ๋์จ๋ค๋๊น. ์ฃผ๋ชฉํ๊ธฐ๋ฅผ.
1.4.3. Testing Smart Pointers for Nullness : ์ค๋งํธ ํฌ์ธํฐ์ ๋๋ฏธ(dumb)์์ null ์ฌ๋ถ๋ฅผ ์๊ณ ์ถ์ด! ¶
์ฐ๋ฆฌ๋ ์ค๋งํธ ํฌ์ธํฐ ์ฌ์ฉ์์ ํ์ํ ๊ฒ๋ค์ธ ์์ฑ(create), ํ๊ดด(destroy), ๋ณต์ฌ(copy), ํ ๋น(assign), ์ญ์ฐธ์กฐ(dereference)์ ๊ดํด์ ๋
ผ์ํ๋ค. ๊ทธ๋ ์ง๋ง ์ฐ๋ฆฌ๊ฐ ์์ง ์ํ๊ฒ์ด ์๋ค. ๋ฐ๋ก ์ค๋งํธ ํฌ์ธํฐ์ null์ฌ๋ถ๋ฅผ ์๊ณ ์ถ์๊ฒ ๋ฐ๋ก ๊ทธ๊ฒ์ด๋ค. ์ง๊ธ๊น์ง์ ์ง์๊น์ง ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ๊ตฌํํ๋ค๊ณ ํ๊ณ , ๋ค์์ ์ฝ๋๋ฅผ ์์ (?) ํ๊ณ ์ ํ ๋
์ด๊ฒ ์ฐธ ๋ฌด์์ด ์ผ์ด์ง ์์๊ฐ?
~cpp SmartPtr<TreeNode> ptn; ... if (ptn == 0) ... // ์๋ฌ! if (ptn) ... // ์๋ฌ! if (!ptn) ... // ์๋ฌ!
isNull ํจ์๋ฅผ ์ถ๊ฐํ๋ฉด ์ฝ๊ฒ ํด๊ฒฐ ๋ ๊ฒ ๊ฐ๋ค. ํ์ง๋ง ์ด๊ฒ์ ์ค๋งํธ ํฌ์ธํฐ๊ฐ ๋๋ฏธ(dumb) ํฌ์ธํฐ์ ๊ฐ์ด ์ด๋ค๋ ๊ฐ๋
์ ๋ฐํ๋ ๊ฒ์ด๋ค. ๊ทธ๋์ ์์์ (implicit) ํ๋ณํ์ผ๋ก ํด๊ฒฐํด ๋ณธ๋ค.
~cpp
template<class T>
class SmartPtr {
public:
...
operator void*(); // ์ค๋งํธ ํฌ์ธํฐ๊ฐ null์ด๋ฉด 0๋ฅผ ๋ฐํํ๊ณ returns 0 if the smart
... // ์๋๋ฉด 0๊ฐ ์๋ ๊ฐ์ ๋ฐํํ๋ค.
};
SmartPtr<TreeNode> ptn;
...
if (ptn == 0) ... // ์ฌ๋ฐ๋ฅด๋ค.
if (ptn) ... // ์ญ์๋
if (!ptn) ... // ์ข์์ด! ^^
~cpp
ifstream inputFile("datafile.dat");
if (inputFile) ... // inputFile์ด ์ ์ด๋ ธ๋๊ฐ์ ๊ดํด์
// ํ์ธํด ๋ณธ๋ค.
~cpp SmartPtr<Apple> pa; SmartPtr<Orange> po; ... if (pa == po) ... // ์ด๊ฒ ์ปดํ์ผ์ด ๋๋จ ๋ง์ด๋ค!
void*์ ํ๋ณํ์(conversion-to-void*) ๋ชจํธ์ฑ์ ํผํ๊ธฐ ์ํด const void* ํ๋ณํ์ด๋, ๋ค๋ฅธ ์ฌ๋๋ค์ bool ํ๋ณํ์ ๊ถํ๋ค. ํ์ง๋ง ์ด๋ฐ ๋ฐฉ๋ฒ๋ ํ๋ณํ๋ค์ ์์ด ์ฐ๋ฉด์ ๋น๊ตํ๋ฉด์(mixed-type comparisons) ๋ฐ์ํ๋ ๋ฌธ์ ์ญ์ ํด๊ฒฐํ ์ ์๋ค.
ํ ๋ฐ์ ๋ฌผ๋ฌ์์, ํ๋ณํ์ด ์๋ operator! ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด ๋ณด์. operator!๋ฅผ overload์์ผ ์ค๋งํธ ํฌ์ธํฐ๊ฐ null์ธ๊ฒฝ์ฐ true๋ฅผ ๋ฐํํ๋ค๊ณ ํด๋ณด์.
ํด๋ผ์ด์ธํธ๋ค์ ์ด๋ ๊ฒ ์ ์ฉํ ๊ฒ์ด๋ค.
~cpp
template<class T>
class SmartPtr {
public:
...
bool operator!() const; // ์ค๋งํธ ํฌ์ธํฐ๊ฐ null์ผ๋ returns true if and only
... // if the smart ptr is null
};
{{{~c












