AcceleratedC++/Chapter10 | AcceleratedC++/Chapter12 |
1. Chapter 11 Defining abstract data types ¶
3μ₯μμ μμ±ν Student_info νμ
μ 볡μ¬, λμ
, μλ©Έμμ μ΄λ€ μΌμ΄ μνλλμ§ λͺ
μΈλμ΄μμ§ μμ.
μ€μ λ‘ ν΄λμ€λ₯Ό μ μν κ²½μ°μλ ν΄λμ€μ μμ±, 볡μ¬, λμ , μλ©Έμ κ³ λ €νμ¬ μ€κ³λμ΄μΌνλ€.
μ΄μ₯μμλ STL vectorν΄λμ€μ μ½μ λ²μ μ λ§λ€μ΄ 보면μ μΌλ°μ μΈ ννμ μλ£νμ λ§λλ λ°©μμ μ΅νλ€.
μ€μ λ‘ ν΄λμ€λ₯Ό μ μν κ²½μ°μλ ν΄λμ€μ μμ±, 볡μ¬, λμ , μλ©Έμ κ³ λ €νμ¬ μ€κ³λμ΄μΌνλ€.
μ΄μ₯μμλ STL vectorν΄λμ€μ μ½μ λ²μ μ λ§λ€μ΄ 보면μ μΌλ°μ μΈ ννμ μλ£νμ λ§λλ λ°©μμ μ΅νλ€.
1.1. 11.1 The Vec class ¶
ν΄λμ€λ₯Ό μ€κ³ν λμλ μ°μ μΈν°νμ΄μ€λ₯Ό κ²°μ ν΄μΌνλ€. μΈν°νμ΄μ€μ κ²°μ μλ μ€μ λ‘ κ·Έ κ°μ²΄λ₯Ό μ΄μ©ν νλ‘κ·Έλ¨μ μμ±ν΄λ³΄λ κ²μ΄ μ’λ€.
~cpp //vector μμ± vector<Student_info> vs; vector<double> v(100); //vectorκ° μ¬μ©νλ νμ μ μ΄λ₯΄μ μ»λλ€. vector<Student_info>::const_iterator b, e; vector<Student_info>::size_type i = 0; //vectorμ κ°μμλ₯Ό μ΄ν΄λ³΄κΈ° μν΄, size λ° index μ°μ°μλ₯Ό μ¬μ© for(i = 0; i != vs.size(); ++1) cout<<vs[i].name(); //첫λ²μ¬ μμμ λ§μ§λ§ μμμ λν λ°λ³΅μ λ¦¬ν΄ b=vs.begin(); e=vs.end();μ΄μμ κ²λ€μ΄ μ΄μ₯μμ ꡬνν vector μ clone λ²μ μΈ Vec ν΄λμ€λ₯Ό ꡬνν λ©μλλ€μ΄λ€.
1.2.1. 11.2.1 λ©λͺ¨λ¦¬ ν λΉ ¶
μ°μ°μ κ²°μ ννμλ μ΄λ€ λ°©μμΌλ‘ Vecλ₯Ό ꡬνν μ§λ₯Ό κ²°μ νλ κ²μ΄λ€.
μ¬κΈ°μλ template classλ₯Ό μ΄μ©νλ€.
ν νλ¦Ώμ ν¨μλΏλ§ μλλΌ ν΄λμ€μμλ μ¬μ©νλ κ²μ΄ κ°λ₯νλ€.
sizeλ begin, end λ₯Ό ν΅ν΄μ κ·Έ ν¬κΈ°λ₯Ό ꡬνλ κ²μ΄ κ°λ₯νλ―λ‘ μ¬κΈ°μλ 첫 μμμ μ£Όμ, λ§μ§λ§ μμλ₯Ό νλ μ§λ μ£Όμλ₯Ό μ μ₯νκ³ κ°μλ κ³μ°μ ν΅ν΄μ ꡬννλ€.
λ°λΌμ μ΄λ€ νμ μ΄ Vecμμ μ¬μ©λλμ§λ μ μλΆκ° instiation λκΈ° μ μλ μ μ μλ€.
μ¬κΈ°μλ template classλ₯Ό μ΄μ©νλ€.
ν νλ¦Ώμ ν¨μλΏλ§ μλλΌ ν΄λμ€μμλ μ¬μ©νλ κ²μ΄ κ°λ₯νλ€.
~cpp template <class T> class Vec { public: //interface private: //implementation };begin, end, size ν¨μλ₯Ό ꡬνν΄μΌ νλ―λ‘ μ΄λ¬ν μμ μ μν΄μ 첫 μμμ μ£Όμ, λ§μ§λ§ μμλ₯Ό νλ μ§λ μ£Όμ, μμλ€μ κ°μλ₯Ό μ μ₯ν μ μμ΄μΌνλ€.
sizeλ begin, end λ₯Ό ν΅ν΄μ κ·Έ ν¬κΈ°λ₯Ό ꡬνλ κ²μ΄ κ°λ₯νλ―λ‘ μ¬κΈ°μλ 첫 μμμ μ£Όμ, λ§μ§λ§ μμλ₯Ό νλ μ§λ μ£Όμλ₯Ό μ μ₯νκ³ κ°μλ κ³μ°μ ν΅ν΄μ ꡬννλ€.
~cpp template <class T> class Vec { public: //interface private: T* data; // 첫λ²μ§Έ μμ T* limit; // λ§μ§λ§ μμμμ νλλ₯Ό μ§λ κ³³μ ν¬μΈν° };ν νλ¦Ώμ λ¨μ§ νμΌ λΏμ΄λ©°, μ¬μ©ν λ type parameterλ‘ μ€ νμ λ°λΌμ μ€μ μ ν΄λμ€λ₯Ό μμ±νλ€.
λ°λΌμ μ΄λ€ νμ μ΄ Vecμμ μ¬μ©λλμ§λ μ μλΆκ° instiation λκΈ° μ μλ μ μ μλ€.
1.2.2. 11.2.2 μμ±μ(Constructor) ¶
μμ μΈν°νμ΄μ€ λͺ
μΈμμ μλμ 2κ°μ§λ₯Ό κ°λ₯νκ² νλλ‘ νκΈ° λλ¬Έμ μμ±μ 2κ°λ μ΅μν ꡬνν΄μΌνλ€.
μΈμμ κΈ°λ³Ένμ μ§μ ν΄μ£Όλ©΄ νκ°μ ν¨μμ μλ‘λ 2κ°μ§μ μμ±μμ μν μ ν μ μκΈ° λλ¬Έμ νΈλ¦¬νλ€.
explicit ν€μλ
μμ±μκ° νλμ μΈμλ₯Ό λ°λ κ²½μ°. μΌλ°μ μΈ λμ μμ±μμ νΌμ©μ΄ λ κ°λ₯μ±μ΄ μ‘΄μ¬νκΈ° λλ¬Έμ λͺ μμ μΈ μμ±λ§μ νμ©μν€λ λ°©λ²μ΄λ€. (12.2 μ μμ μμΈν λ Όμ)
~cpp Vec<Student_info> vs; // default constructor Vec<Student_info> vs(100); // Vecμ μμμ ν¬κΈ°λ₯Ό μ·¨νλ μμ±μ // νμ€ vector ν΄λμ€λ ν¬κΈ°μ ν¨κ» μ΄κΈ°ν μμλ₯Ό μΈμλ‘ λ°λ μμ±μλ μ 곡νλ€.
~cpp template <class T> class Vec { public: Vec() { create(); } // μμ§μΌλ‘μ λ ꡬνλΆλΆμμ μ ν΄μ§ κ²μ΄ μκΈ° λλ¬Έμ μμμ μΌλ‘ ν¨μλ₯Ό λ§λ€μ΄μ λ£μλ€. explicit Vec(size_type n, const T& val = T()) { create(n, val); } private: T* data; // 첫λ²μ§Έ μμ T* limit; // λ§μ§λ§ μμμμ νλλ₯Ό μ§λ κ³³μ ν¬μΈν° };2λ²μ§Έ μμ±μλ μ΄κΈ°νμ μΈμλ‘ μΈμ νλΌλ©ν°μΈ Tμ μμ±μλ₯Ό μ΄μ©νλ€.
μΈμμ κΈ°λ³Ένμ μ§μ ν΄μ£Όλ©΄ νκ°μ ν¨μμ μλ‘λ 2κ°μ§μ μμ±μμ μν μ ν μ μκΈ° λλ¬Έμ νΈλ¦¬νλ€.
explicit ν€μλ
μμ±μκ° νλμ μΈμλ₯Ό λ°λ κ²½μ°. μΌλ°μ μΈ λμ μμ±μμ νΌμ©μ΄ λ κ°λ₯μ±μ΄ μ‘΄μ¬νκΈ° λλ¬Έμ λͺ μμ μΈ μμ±λ§μ νμ©μν€λ λ°©λ²μ΄λ€. (12.2 μ μμ μμΈν λ Όμ)
~cpp Vec<int> vi(100); // Working. int λ₯Ό ν΅ν΄ λͺ μμ μΈ μμ± Vec<int> vi = 100; // not working. μ묡μ μΌλ‘ Vecλ₯Ό μμ±νκ³ κ·Έ κ°μ vi μ 볡μ¬νλ€. refer 11.3.3
1.2.3. 11.2.3 νμ μ μ ¶
const_iterator, iteratorλ₯Ό μ μν΄μΌν¨.
back_inserter(T)ν¨μλ₯Ό ν΅ν΄μ λμ μΌλ‘ ν¬κΈ°λ₯Ό λ³κ²½μν€κΈ° μν΄μ value_type, push_back νμ μ μ μν¨. (value_type μ νμ¬ μ μ₯λ μμκ° μ΄λ€ νμ μΈμ§λ₯Ό μλ €μ€)
listμ λ°λ³΅μλ₯Ό ꡬννλ κ²½μ°λΌλ©΄ ++ μ°μ°μ ν΅ν΄μ λ Έλλ‘ μ°κ²°λ λ€μ λ Έλλ₯Ό 리ν΄νλ ν¨μλ₯Ό μ€λ²λ‘λ©ν΄μΌνλ, μ¬κΈ°μλ λ°°μ΄μ μμλ₯Ό κ°λ¦¬ν€λ―λ‘ λ¨μμ΄ ν¬μΈν°λ₯Ό 리ν΄νλ κ² λ§μΌλ‘ μ°λ¦¬λ μμ μ κ·Ό λ°λ³΅μλ₯Ό ꡬννλ κ²μ΄ κ°λ₯νλ€.
value_typeμ Tκ° λμ΄μΌνλ κ²μ λΉμ°νλ€. λ°°μ΄μ κ°μλ₯Ό νννλ size_typeμ cstddef μ μ‘΄μ¬νλ size_tλ‘μ μ μνλ κ²μ΄ ν©λΉνλ€.
back_inserter(T)ν¨μλ₯Ό ν΅ν΄μ λμ μΌλ‘ ν¬κΈ°λ₯Ό λ³κ²½μν€κΈ° μν΄μ value_type, push_back νμ μ μ μν¨. (value_type μ νμ¬ μ μ₯λ μμκ° μ΄λ€ νμ μΈμ§λ₯Ό μλ €μ€)
listμ λ°λ³΅μλ₯Ό ꡬννλ κ²½μ°λΌλ©΄ ++ μ°μ°μ ν΅ν΄μ λ Έλλ‘ μ°κ²°λ λ€μ λ Έλλ₯Ό 리ν΄νλ ν¨μλ₯Ό μ€λ²λ‘λ©ν΄μΌνλ, μ¬κΈ°μλ λ°°μ΄μ μμλ₯Ό κ°λ¦¬ν€λ―λ‘ λ¨μμ΄ ν¬μΈν°λ₯Ό 리ν΄νλ κ² λ§μΌλ‘ μ°λ¦¬λ μμ μ κ·Ό λ°λ³΅μλ₯Ό ꡬννλ κ²μ΄ κ°λ₯νλ€.
value_typeμ Tκ° λμ΄μΌνλ κ²μ λΉμ°νλ€. λ°°μ΄μ κ°μλ₯Ό νννλ size_typeμ cstddef μ μ‘΄μ¬νλ size_tλ‘μ μ μνλ κ²μ΄ ν©λΉνλ€.
~cpp template <class T> class Vec { public: typedef T* iterator; typedef const T* const_iterator; typedef size_t size_type; typedef T value_type; Vec() { create(); } // μμ§μΌλ‘μ λ ꡬνλΆλΆμμ μ ν΄μ§ κ²μ΄ μκΈ° λλ¬Έμ μμμ μΌλ‘ ν¨μλ₯Ό λ§λ€μ΄μ λ£μλ€. explicit Vect(size_type n, const T& val = T()) { create(n, val); } private: iterator data; // 첫λ²μ§Έ μμ iterator limit; // λ§μ§λ§ μμμμ νλλ₯Ό μ§λ κ³³μ ν¬μΈν° };μ μ ν typedefλ₯Ό μΆκ°νκ³ , λ©€λ² λ°μ΄ν°μ νλ μ¬κΈ°μ λ§μΆμ΄μ λ³κ²½νμμ.
1.2.4. 11.2.4 μΈλ±μ€ λ° size ¶
~cpp for (i = 0; i != vs.size(); ++) cout<<vs[i].name();μκΈ°μ μ°μ°μ κ°λ₯νκ² νκΈ° μν΄μλ operator[], size() ν¨μλ₯Ό μ μ ν΄μΌνλ€.
μ°μ°μ μ€λ²λ‘λ©(operator overload)
μ€λ²λ‘λ μ°μ°μμ λͺ μΉμ operatorop μ ννλ‘ λνλλ€. μ¦
~cpp []
μ κ²½μ°μλ ~cpp operator[]
λ‘ λνλΌ μ μλ€.λ§μ½ μ€λ²λ‘λ μ°μ°μκ° λ©€λ²ν¨μκ° μλλΌλ©΄(friend ν¨μ) μ’μΈ‘ νΌμ°μ°μλ 첫λ²μ§Έ μΈμ, μ°μΈ‘ νΌμ°μ°μλ λλ²μ¬ μΈμλ‘ λνλΌ μ μλ€.
λ§μ½ λ©€λ² ν¨μλ‘ μ°μ°μκ° μ μ λμ΄ μλ€λ©΄ μ’μΈ‘ νΌμ°μ°μλ ν¨μλ₯Ό νΈμΆν κ°μ²΄λ‘ κ°μ£Όλκ³ μ€λ²λ‘λ μ°μ°μλ μΈμλ‘ μ°μΈ‘μ νΌμ°μ°μλ§μ μΈμλ‘ μ·¨νλ€.
~cpp []
μ°μ°μ μΈμλ‘ size_typeμ μ·¨νκ³ , 리ν΄κ°μΌλ‘ value_typeμ λ νΌλ°μ€λ₯Ό μ·¨ν΄μΌν κ²μ΄λ€.~cpp template <class T> class Vec { public: typedef T* iterator; typedef const T* const_iterator; typedef size_t size_type; typedef T value_type; Vec() { create(); } // μμ§μΌλ‘μ λ ꡬνλΆλΆμμ μ ν΄μ§ κ²μ΄ μκΈ° λλ¬Έμ μμμ μΌλ‘ ν¨μλ₯Ό λ§λ€μ΄μ λ£μλ€. explicit Vect(size_type n, const T& val = T()) { create(n, val); } size_type size() const { return limit - data; } T& operator[](size_type i) { return data[i]; } const T& operator[](size_type i) const { return data[i]; }; // μ΄κ²½μ°μλ λ νΌλ°μ€λ₯Ό μ°λ μ΄μ λ μ±λ₯μμ μ΄μ λλ¬Έμ΄λ€. private: iterator data; // 첫λ²μ§Έ μμ iterator limit; // λ§μ§λ§ μμμμ νλλ₯Ό μ§λ κ³³μ ν¬μΈν° };operator[] μ 2κ°μ§ λ²μ μ μ€λ²λ‘λ© ν μ μλ κ·Όκ±°
λͺ¨λ λ©€λ²ν¨μλ μ묡μ μΌλ‘ νκ°μ§μ μΈμλ₯Ό λ λ°λλ€. κ·Έκ²μ κ·Έ ν¨μλ₯Ό νΈμΆν κ°μ²΄μΈλ°, μ΄κ²½μ° κ·Έ κ°μ²΄κ° constμ΄κ±°λ const κ° μλ λ²μ 2κ°μ§κ° μ‘΄μ¬νλ κ²μ΄ κ°λ₯νκΈ° λλ¬Έμ parameter specification μ΄ λμΌνμ§λ§ μ€λ²λ‘λ©μ΄ κ°λ₯νλ€.
1.2.5. 11.2.5 λ°λ³΅μλ₯Ό 리ν΄νλ μ°μ° ¶
~cpp template <class T> class Vec { public: typedef T* iterator; typedef const T* const_iterator; typedef size_t size_type; typedef T value_type; Vec() { create(); } // μμ§μΌλ‘μ λ ꡬνλΆλΆμμ μ ν΄μ§ κ²μ΄ μκΈ° λλ¬Έμ μμμ μΌλ‘ ν¨μλ₯Ό λ§λ€μ΄μ λ£μλ€. explicit Vect(size_type n, const T& val = T()) { create(n, val); } size_type size() const { return limit - data; } T& operator[](size_type i) { return data[i]; } const T& operator[](size_type i) const { return data[i]; }; // μ΄κ²½μ°μλ λ νΌλ°μ€λ₯Ό μ°λ μ΄μ λ μ±λ₯μμ μ΄μ λλ¬Έμ΄λ€. //λ°λ³΅μλ€μ 리ν΄νλ μλ‘μ΄ ν¨μλ€ iterator begin() { return data; } const_iterator begin() const { return data; } iterator end() { return limit; } const_iterator end() const { return limit; } private: iterator data; // 첫λ²μ§Έ μμ iterator limit; // λ§μ§λ§ μμμμ νλλ₯Ό μ§λ κ³³μ ν¬μΈν° };
1.3. 11.3 Copy control ¶
μ°λ¦¬κ° 볡μ¬, λμ
, μλ©Έμ νλ μΌμ λν΄μ λͺ
μμ μΌλ‘ μ νμ§ μμΌλ©΄ μ»΄νμΌλ¬λ μ ν΄μ§ μμ λ§μ λ°©λ²μΌλ‘ μ΄λ° μΌμ νλ μ μλ₯Ό λ§λ€μ΄μ μλνκ² λλ€.
μ¬μ€ μ΄λ κ² μμΈν κ°μ²΄μ νλμμμ κ·μ ν μ μλ μΈμ΄λ‘λ C++μ΄ μ μΌνλ€. (κ·Έλ§νΌ ν΄λμ€λ₯Ό μμ±ν λ λ§μ κ²λ€μ΄ κ³ λ €λμ΄μΌνλ€.)
μ¬μ€ μ΄λ κ² μμΈν κ°μ²΄μ νλμμμ κ·μ ν μ μλ μΈμ΄λ‘λ C++μ΄ μ μΌνλ€. (κ·Έλ§νΌ ν΄λμ€λ₯Ό μμ±ν λ λ§μ κ²λ€μ΄ κ³ λ €λμ΄μΌνλ€.)
1.3.1. 11.3.1 Copy μμ±μ ¶
implicit copy constructor
explicit copy constructor
λ³΅μ¬ μμ±μλ μμ±μμ μ΄λ¦μ κΈ°ν μμ±μμ κ°μΌλ μΈμλ‘ μμ μ΄ νΈμΆλ κ°μ²΄μ νμ μ κ°λ μμ±μλ₯Ό μλ―Ένλ€.
ν¨μμ μΈμλ₯Ό 볡μ¬νλ κ²μ ν¬ν¨ν΄μ, 볡μ¬λ³Έμ λ§λ λ€λ μλ―Έλ₯Ό μ μνκ³ μκΈ° λλ¬Έμ λ§€κ°λ³μλ₯Ό λ νΌλ°μ€ νμ μΌλ‘ νλ κ²μ΄ μ’λ€.
λ³΄ν΅ λν΄νΈ λ³΅μ¬ μμ±μμ κ²½μ°μλ ν΄λμ€μ λ©€λ² λ³μλ€μ λ¨μν 볡μ¬λ§ νκ² λ©λλ€. μ΄λ λ§μ½ κ·Έ λ©€λ² λ³μκ° ν¬μΈν°μ ννλΌκ³ νλ€λ©΄ λ¬Έμ κ° λ°μνκ² λλ€.
μ΄ κ²½μ° νμͺ½μ κ°μ²΄κ° μμ λκ±°λ μλ©Έλλ©΄ μ΄λ₯Ό 볡μ¬ν κ°μ²΄λ κ·Έ μν₯μ λ°κ²λκΈ° λλ¬Έμ΄λ€.
λ°λΌμ ν¬μΈν°μ κ²½μ° μλ‘μ΄ μ£Όμ 곡κ°μ ν λΉλ°κ³ κ·Έ λμμ΄ λλ κ°μ 볡μ¬ν΄μΌμ§ μ΄λ° λ¬Έμ κ° λ°μνμ§ μλλ€.
μμ λ€λ₯Έ μμ±μμ λ§μ°¬κ°μ§λ‘ create() ν¨μλ₯Ό μ΄μ©ν΄μ 볡μ¬λ₯Ό ννλλ‘ λ§λ λ€.
~cpp vector<int> vi; double d; d = median (vi); // copy constructor work string line; vector<string> words = split(words); // copy constructor work
explicit copy constructor
~cpp vector<Student_info> vs; vector<Student_info> v2 = vs; // copy constructor work (from vs to v2)λ³΅μ¬ μμ±μ
λ³΅μ¬ μμ±μλ μμ±μμ μ΄λ¦μ κΈ°ν μμ±μμ κ°μΌλ μΈμλ‘ μμ μ΄ νΈμΆλ κ°μ²΄μ νμ μ κ°λ μμ±μλ₯Ό μλ―Ένλ€.
ν¨μμ μΈμλ₯Ό 볡μ¬νλ κ²μ ν¬ν¨ν΄μ, 볡μ¬λ³Έμ λ§λ λ€λ μλ―Έλ₯Ό μ μνκ³ μκΈ° λλ¬Έμ λ§€κ°λ³μλ₯Ό λ νΌλ°μ€ νμ μΌλ‘ νλ κ²μ΄ μ’λ€.
~cpp template <class T> class Vec { public: Vec(const Vec& v); // copy constructor // μ΄μ κ³Ό κ°μ };
λ³΄ν΅ λν΄νΈ λ³΅μ¬ μμ±μμ κ²½μ°μλ ν΄λμ€μ λ©€λ² λ³μλ€μ λ¨μν 볡μ¬λ§ νκ² λ©λλ€. μ΄λ λ§μ½ κ·Έ λ©€λ² λ³μκ° ν¬μΈν°μ ννλΌκ³ νλ€λ©΄ λ¬Έμ κ° λ°μνκ² λλ€.
μ΄ κ²½μ° νμͺ½μ κ°μ²΄κ° μμ λκ±°λ μλ©Έλλ©΄ μ΄λ₯Ό 볡μ¬ν κ°μ²΄λ κ·Έ μν₯μ λ°κ²λκΈ° λλ¬Έμ΄λ€.
λ°λΌμ ν¬μΈν°μ κ²½μ° μλ‘μ΄ μ£Όμ 곡κ°μ ν λΉλ°κ³ κ·Έ λμμ΄ λλ κ°μ 볡μ¬ν΄μΌμ§ μ΄λ° λ¬Έμ κ° λ°μνμ§ μλλ€.
μμ λ€λ₯Έ μμ±μμ λ§μ°¬κ°μ§λ‘ create() ν¨μλ₯Ό μ΄μ©ν΄μ 볡μ¬λ₯Ό ννλλ‘ λ§λ λ€.
~cpp template <class T> class Vec { public: Vec(const Vec& v) { create(v.begin(), v.end() ); } // copy constructor // μ΄μ κ³Ό κ°μ };
1.3.2. 11.3.2 λμ (Assignment) ¶
λμ
μ°μ°μ(assignment operator)
operator=() μ μ¬λ¬κ°μ§ μΈμ€ν΄μ€μ€μμ μΈμλ‘ μμ μ ν΄λμ€ ν μ체μ λν const λ νΌλ°μ€λ₯Ό μ·¨νλ ννλ₯Ό λμ μ°μ°μλΌ μΉνλ€.
리ν΄κ°μ C++ κΈ°λ³Έ λμ μ°μ°μμμ μΌκ΄μ±μ μ μ§λ₯Ό μν΄μ μ°μ°μμ μΈμͺ½ν(left-hand side)μλν λ νΌλ°μ€λ₯Ό μ·¨νλ€.
λμ μ°μ°μλ λ³΅μ¬ μ°μ°μμ λ¬λ¦¬ μΌμͺ½νμ μ κ±°νκ³ μλ‘μ΄ κ°μΌλ‘ λ체μν΅λλ€. λ³΅μ¬ μμ±μλ μν μμ μ μΌμͺ½νμ κ°μ²΄κ° μ²μ λ§λ€μ΄μ§ μνμ΄κΈ° λλ¬Έμ ν΄μ ν λμμ΄ μμ§λ§, λμ μ°μ°μλ κΈ°μ‘΄λ°μ΄ν°κ° μλ μνμμλ λμ μ ν μ μκΈ° λλ¬Έμ λ³΅μ¬ μμ±μμ λΉμ·νκ² κ΅¬μ±λμ΄μΌ νλ€.
λν μκΈ° λμ (self-assignment)μ μν κ³ λ €κ° νμνλ€.
operator=() μ μ¬λ¬κ°μ§ μΈμ€ν΄μ€μ€μμ μΈμλ‘ μμ μ ν΄λμ€ ν μ체μ λν const λ νΌλ°μ€λ₯Ό μ·¨νλ ννλ₯Ό λμ μ°μ°μλΌ μΉνλ€.
리ν΄κ°μ C++ κΈ°λ³Έ λμ μ°μ°μμμ μΌκ΄μ±μ μ μ§λ₯Ό μν΄μ μ°μ°μμ μΈμͺ½ν(left-hand side)μλν λ νΌλ°μ€λ₯Ό μ·¨νλ€.
~cpp template <class T> class Vec { public: Vec& operator=(const Vec&); // copy constructor // μ΄μ κ³Ό κ°μ };λμ μ°μ°μ μ€λ²λ‘λ©μ μ£Όμν΄μΌν μ¬ν
λμ μ°μ°μλ λ³΅μ¬ μ°μ°μμ λ¬λ¦¬ μΌμͺ½νμ μ κ±°νκ³ μλ‘μ΄ κ°μΌλ‘ λ체μν΅λλ€. λ³΅μ¬ μμ±μλ μν μμ μ μΌμͺ½νμ κ°μ²΄κ° μ²μ λ§λ€μ΄μ§ μνμ΄κΈ° λλ¬Έμ ν΄μ ν λμμ΄ μμ§λ§, λμ μ°μ°μλ κΈ°μ‘΄λ°μ΄ν°κ° μλ μνμμλ λμ μ ν μ μκΈ° λλ¬Έμ λ³΅μ¬ μμ±μμ λΉμ·νκ² κ΅¬μ±λμ΄μΌ νλ€.
λν μκΈ° λμ (self-assignment)μ μν κ³ λ €κ° νμνλ€.
~cpp template<class T> Vec<T>& Vec<T>::operator=(const Vec& rhs) { // self-assignment check if (&rhs != this) { //lhs memory deallocation uncreate(); create(rhs.begin(), rhs.end()); { return *this; }
- ν€λνμΌμμμ 리ν΄νμ
μ΄ Vec& λ‘ μ¬μ©λμμ
ν νλ¦Ώμ μ€μ½ν μμμλ νμ λ§€κ°λ³μλ₯Ό μλ΅νλ μμ λ μ¬μ΄ ννμ μ¬μ©ν μ μλ€.
Vec::operator= μ΄ μλλΌ, Vec<T>::operator= κ° μλμ μ΄λ¦μ΄λ€. κ·Έλ¬λ μΌλ¨ operator=κ° Vec<T>μ λ©€λ²λΌλ μ¬μ€μ΄ λ°νμ§λ©΄ λμ΄μ ν νλ¦Ώ νμ μλ₯Ό λ°λ³΅ν νμκ° μλ€.
- this ν€μλμ μ¬μ©
thisλ λ©€λ²ν¨μ μμμ μ ν¨νλ€. thisλ λ©€λ²ν¨μλ₯Ό νΈμΆμν¨ κ°μ²΄μ ν¬μΈν°λ₯Ό 리ν΄νλ€.
λ§μ½ this ν€μλλ‘ μκΈ° λμ 체ν¬λ₯Ό νμ§ μμ κ²½μ°μλ μ€λ₯Έμͺ½ κ°μ²΄λ₯Ό ν΄μ ν λ€μ λ€μ μΌμͺ½νμ λμ νκ² λλ―λ‘ λ¬Έμ κ° λ°μνκ² λλ€.
- *this μ 리ν΄
μ§μ κ°μ²΄μ λν 리ν΄μ ν΄μλ μλλ€. μ§μ κ°μ²΄λ₯Ό 리ν΄νλ©΄ κ°μ²΄μ μ‘΄μ¬ scopeλ₯Ό λ²μ΄λκΈ° λλ¬Έμ μ¬λ°λ₯Έ λμμ 보μ₯νμ§ λͺ»νλ€.
1.3.3. 11.3.3 λμ μ μ΄κΈ°νκ° μλλ€ ¶
C++μ = κ° κ°μ²΄μ μ΄κΈ°ν, λ³΅μ¬ μμ λμΌνκ² μ¬μ©λκΈ° λλ¬Έμ λ³΅μ¬ μμ±μμ, λμ
μ°μ°μμ ꡬλΆμ΄ μλ€.
= κ° μ΄κΈ°ν λμ§ μμ κ°μ²΄μ μ¬μ©λλ©΄ λ³΅μ¬ μμ±μλ‘, μ΄κΈ°νλ κ°μ²΄μ μ¬μ©λλ©΄ λμ μ°μ°μλ‘ μ¬μ©λλ€.
μμ±μμ 2κ°μ§ μ©λ²
리ν΄κ°μμμ λ³΅μ¬ μμ±μμ μ¬μ©, λμ μ°μ°μμ μ¬μ©
= κ° μ΄κΈ°ν λμ§ μμ κ°μ²΄μ μ¬μ©λλ©΄ λ³΅μ¬ μμ±μλ‘, μ΄κΈ°νλ κ°μ²΄μ μ¬μ©λλ©΄ λμ μ°μ°μλ‘ μ¬μ©λλ€.
μ΄κΈ°ν μν© | * λ³μ μ μΈμ * ν¨μ μ§μ μ, ν¨μ λ§€κ°λ³μ * ν¨μ 리ν΄κ° * μμ±μ μ΄κΈ° μ€μ μ |
μμ±μμ 2κ°μ§ μ©λ²
~cpp string url_ch = "~;/?:@=&$-_.+!*'(),"; string spaces(url_ch.size(), ' ');
리ν΄κ°μμμ λ³΅μ¬ μμ±μμ μ¬μ©, λμ μ°μ°μμ μ¬μ©
~cpp vector<string> split(const string&); vector<string> v; v = split(line); // ν¨μμ μ’ λ£μ μμ κ°μ²΄λ₯Ό 볡μ¬μμ±μλ‘ μμ± // μμ±λ μμ κ°μ²΄λ₯Ό λμ μ°μ°μκ° v μ λμ
1.3.4. 11.3.4 μλ©Έμ(Destructor) ¶
μλ©Έμ(destructor)
λμ ν λΉμΌλ‘ μμ±λ κ°μ²΄λ delete ν€μλλ‘ μ κ±°νκΈ° μ μλ λ©λͺ¨λ¦¬ 곡κ°μμ μμ λμ§ μλλ°, κ°μ²΄ λ©€λ²λ³μλ‘ λμ ν λΉμ΄ λ λ³μκ° μ‘΄μ¬νλ€λ©΄ κ°μ²΄μ ν΄μ μμ μ΄ κ³΅κ°μ λ©λͺ¨λ¦¬μμ ν΄μ ν΄μ£Όμ΄μΌ νλ€.
μλ©Έμμ ννλ μμ±μμ λ§μ°¬κ°μ§λ‘ λ°ννμ΄ μμΌλ©° κ°μ²΄ νλͺ κ³Ό λμΌν ν¨μλͺ μ κ°λ λμ μ 첫 κΈμλ‘ ~λ₯Ό κ°μ ΈμΌ νλ€.
λμ ν λΉμΌλ‘ μμ±λ κ°μ²΄λ delete ν€μλλ‘ μ κ±°νκΈ° μ μλ λ©λͺ¨λ¦¬ 곡κ°μμ μμ λμ§ μλλ°, κ°μ²΄ λ©€λ²λ³μλ‘ λμ ν λΉμ΄ λ λ³μκ° μ‘΄μ¬νλ€λ©΄ κ°μ²΄μ ν΄μ μμ μ΄ κ³΅κ°μ λ©λͺ¨λ¦¬μμ ν΄μ ν΄μ£Όμ΄μΌ νλ€.
μλ©Έμμ ννλ μμ±μμ λ§μ°¬κ°μ§λ‘ λ°ννμ΄ μμΌλ©° κ°μ²΄ νλͺ κ³Ό λμΌν ν¨μλͺ μ κ°λ λμ μ 첫 κΈμλ‘ ~λ₯Ό κ°μ ΈμΌ νλ€.
~cpp template <class T> class Vec { public: ~Vec() { uncreate; } // copy constructor // μ΄μ κ³Ό κ°μ };
1.3.5. 11.3.5 λν΄νΈ μ°μ°(Default operation) ¶
μμ±μ, μλ©Έμ, λ³΅μ¬ μμ±μ, λμ
μ°μ°μλ₯Ό μ¬μ μ νμ§ μμ κ²½μ°μλ μ»΄νμΌλ¬κ° κΈ° μ μλ λ°©μμΌλ‘ μ΄λ° μμ±μμ κΈ°λ³Ένμ λ§λ λ€.
μ΄ κ²½μ° λ©€λ² κ°μ²΄(has-a)μΈ κ²½μ°μλ μ¬κ·μ μΌλ‘ μ΄λ° λν΄νΈ μ°μ°μ μννλ©°, κΈ°λ³Έν(primitive type)μ κ²½μ°μλ κ°μμν λ°©μμΌλ‘ μ΄λ° μ°μ°λ€μ΄ νν΄μ§λ€. κ·Έλ¬λ ν¬μΈν°μ κ²½μ° νΉλ³ν λ€λ₯Έ μΌμ΄ μμ΄λμ§ μμΌλ©°, ν¬μΈν°κ° κ°λ¦¬ν€λ 곡κ°μ ν΄μ λμ§ μλλ€.
default constructor λ₯Ό μ¬μ©νκΈ° μν΄μλ κ°μ²΄μ λ©€λ²λ€μ΄ λν΄νΈ μμ±μλ₯Ό κ°μ§ κ²½μ°μλ§ μ μμ μΈ λμμ 보μ₯ν μ μλ€.
μΌλ°μ μΌλ‘λ λͺ μμ μΌλ‘ μ μλ λν΄νΈ μμ±μλ₯Ό λ§λλ κ²μ΄ μ’λ€.
μ΄ κ²½μ° λ©€λ² κ°μ²΄(has-a)μΈ κ²½μ°μλ μ¬κ·μ μΌλ‘ μ΄λ° λν΄νΈ μ°μ°μ μννλ©°, κΈ°λ³Έν(primitive type)μ κ²½μ°μλ κ°μμν λ°©μμΌλ‘ μ΄λ° μ°μ°λ€μ΄ νν΄μ§λ€. κ·Έλ¬λ ν¬μΈν°μ κ²½μ° νΉλ³ν λ€λ₯Έ μΌμ΄ μμ΄λμ§ μμΌλ©°, ν¬μΈν°κ° κ°λ¦¬ν€λ 곡κ°μ ν΄μ λμ§ μλλ€.
default constructor λ₯Ό μ¬μ©νκΈ° μν΄μλ κ°μ²΄μ λ©€λ²λ€μ΄ λν΄νΈ μμ±μλ₯Ό κ°μ§ κ²½μ°μλ§ μ μμ μΈ λμμ 보μ₯ν μ μλ€.
μΌλ°μ μΌλ‘λ λͺ μμ μΌλ‘ μ μλ λν΄νΈ μμ±μλ₯Ό λ§λλ κ²μ΄ μ’λ€.
1.3.6. 11.3.6 μΈ λ²μΉ(rule of three) ¶
λ³΅μ¬ μμ±μ λ―Έμ μ | μλ³Έκ³Ό 볡μ¬λ³Έμ λ°μ΄ν°κ° μνΈ μ°Έμ‘°μ νμμΌλ‘ λμνλ€. |
μλ©Έμ λ―Έμ μ | ν¬μΈν° κ°μ²΄κ° μ‘΄μ¬νλ κ²½μ° memory leak μ΄ λ°μ |
ν κ°μ²΄μ λν΄μ λͺ¨λ 볡μ¬λ³Έμ΄ μ λλ‘ λμνλ©΄ μ¬μ μ ν΄μΌν κ²λ€ |
T::T() T::~T() T::T(const T&) T::operator=(const T&) |
Rule of three : λ³΅μ¬ μμ±μ, μλ©Έμ, λμ μ°μ°μκ° λ°μ ν κ΄κ³λ₯Ό κ°λ κ²μ μΌμ»¬μ΄ νννλ λ§μ΄λ€.
1.4. 11.4 Dynamic Vecs ¶
push_backμ ꡬνλ°©μ
push_backμ ꡬνν¨μ μμ΄μ μμ λ°°μ΄μ ν¬κΈ°λ₯Ό ν€μμΌνλλ° μ΄ κ²μ μν΄μ μ¬κΈ°μλ νμμ λ³΄λ€ λ§μ μμ λ°°μ΄μ ν λΉνκ³ νλμ© λ³μλ₯Ό νλλ λ§λ€μ΄μ νμ¬ μ¬μ©κ°λ₯ν λμ κ°λ¦¬ν€λλ° μ΄μ©νκΈ°λ‘ νλ€.
push_backμ ꡬνν¨μ μμ΄μ μμ λ°°μ΄μ ν¬κΈ°λ₯Ό ν€μμΌνλλ° μ΄ κ²μ μν΄μ μ¬κΈ°μλ νμμ λ³΄λ€ λ§μ μμ λ°°μ΄μ ν λΉνκ³ νλμ© λ³μλ₯Ό νλλ λ§λ€μ΄μ νμ¬ μ¬μ©κ°λ₯ν λμ κ°λ¦¬ν€λλ° μ΄μ©νκΈ°λ‘ νλ€.
~cpp template<class T> class Vec { public: size_type size() const { return avail - data; } iterator end() { return avail; } const_iterator end() const { return avail; } void push_back(const T& val) { if (avail == limit) grwo(0; unchecked_append(val); } private: iterator data; iterator avail; iterator limit; }
1.5. 11.5 Flexible memory management ¶
Vecμμ new, delete ν€μλλ₯Ό μ¬μ©νμ§ μλλ€. λ°°μ΄μ newλ‘ ν λΉνκ² λλ©΄ κΈ°λ³Έμ μΌλ‘ μμ±λλ κ°μ²΄μ λν΄νΈ μμ±μλ‘ μ΄κΈ°ν λκΈ° λλ¬Έμ΄λ€. μ΄λ μλ μ°λ¦¬κ° μλν κ²κ³Όλ λ€λ₯Έ λ°©μμΌλ‘ λμνλ€.
λ°λΌμ μ°λ¦¬λ μ’λ μΌλ°μ μΈ ννμ νμ€ μ 곡 λΌμ΄λΈλ¬λ¦¬μ μ‘΄μ¬νλ κ΄λ¦¬μλ₯Ό μ¬μ©νλ€.
λ°λΌμ μ°λ¦¬λ μ’λ μΌλ°μ μΈ ννμ νμ€ μ 곡 λΌμ΄λΈλ¬λ¦¬μ μ‘΄μ¬νλ κ΄λ¦¬μλ₯Ό μ¬μ©νλ€.
<memory> μ allocate<> STLμμ μμμΌν μ€μ λ©μλ
allocate ν΄λμ€μ λΉλ©€λ² ν¨μ μΌλΆ
~cpp template<class T> class allocator { pubilc: T* allocate(size_t); void deallocate(T*, size_t); void construct(T*, T); void destroy(T*); };
allocate, deallocate | μ€μ λ©λͺ¨λ¦¬μ 곡κ°μ ν λΉ, ν΄μ νλ€. κ·Έλ¬λ ν λΉμ μ΄κΈ°νλ νμ§ μλλ€. |
construct, destroy | ν λΉλ λ©λͺ¨λ¦¬ 곡κ°μ μ λΉν λ°μ΄ν° νμ μ μ΄κΈ°ν μν¨λ€. (곡κ°μ allocateλ₯Ό ν΅ν΄μ μ΄λ―Έ ν λΉλ 곡κ°μ΄μ΄μΌ νλ€.) |
allocate ν΄λμ€μ λΉλ©€λ² ν¨μ μΌλΆ
~cpp template<class In, class For> For uninitialized_copy(In, In, For); tempalte<class for, class T> void uninitialized_fill(For, For, const T&);
uninitialized_copy | 첫λ²μ§Έμ λλ²μ§ΈμΈμμ μ€νμ€λ§νΌμ 3λ²μ§Έ μΈμμ 곡κ°μ 볡μ¬νλ€. |
uninitialized_fill | 첫λ²μ§Έμ λλ²μ§Έ μΈμμ 곡κ°μ Tλ‘ μ±μ΄λ€. |
1.5.1. 11.5.1 μ΅μ’ Vec ν΄λμ€ ¶
~cpp //vec.h #ifndef VEC_H #define VEC_H #include <algorithm> #include <cstddef> #include <memory> using std::max; template <class T> class Vec { public: typedef T* iterator; typedef const T* const_iterator; typedef size_t size_type; typedef T value_type; typedef T& reference; typedef const T& const_reference; Vec() { create(); } explicit Vec(size_type n, const T& t = T()) { create(n, t); } Vec(const Vec& v) { create(v.begin(), v.end()); } Vec& operator=(const Vec&); // as defined in 11.3.2/196 ~Vec() { uncreate(); } T& operator[](size_type i) { return data[i]; } const T& operator[](size_type i) const { return data[i]; } void push_back(const T& t) { if (avail == limit) grow(); unchecked_append(t); } size_type size() const { return avail - data; } // changed iterator begin() { return data; } const_iterator begin() const { return data; } iterator end() { return avail; } // changed const_iterator end() const { return avail; } // changed void clear() { uncreate(); } bool empty() const { return data == avail; } private: iterator data; // first element in the `Vec' iterator avail; // (one past) the last element in the `Vec' iterator limit; // (one past) the allocated memory // facilities for memory allocation std::allocator<T> alloc; // object to handle memory allocation // allocate and initialize the underlying array void create(); void create(size_type, const T&); void create(const_iterator, const_iterator); // destroy the elements in the array and free the memory void uncreate(); // support functions for `push_back' void grow(); void unchecked_append(const T&); }; template <class T> void Vec<T>::create() { data = avail = limit = 0; } template <class T> void Vec<T>::create(size_type n, const T& val) { data = alloc.allocate(n); limit = avail = data + n; std::uninitialized_fill(data, limit, val); } template <class T> void Vec<T>::create(const_iterator i, const_iterator j) { data = alloc.allocate(j - i); limit = avail = std::uninitialized_copy(i, j, data); } template <class T> void Vec<T>::uncreate() { if (data) { // destroy (in reverse order) the elements that were constructed iterator it = avail; while (it != data) alloc.destroy(--it); // return all the space that was allocated alloc.deallocate(data, limit - data); } // reset pointers to indicate that the `Vec' is empty again data = limit = avail = 0; } template <class T> void Vec<T>::grow() { // when growing, allocate twice as much space as currently in use size_type new_size = max(2 * (limit - data), ptrdiff_t(1)); // allocate new space and copy existing elements to the new space iterator new_data = alloc.allocate(new_size); iterator new_avail = std::uninitialized_copy(data, avail, new_data); // return the old space uncreate(); // reset pointers to point to the newly allocated space data = new_data; avail = new_avail; limit = data + new_size; } // assumes `avail' points at allocated, but uninitialized space template <class T> void Vec<T>::unchecked_append(const T& val) { alloc.construct(avail++, val); } template <class T> Vec<T>& Vec<T>::operator=(const Vec& rhs) { // check for self-assignment if (&rhs != this) { // free the array in the left-hand side uncreate(); // copy elements from the right-hand to the left-hand side create(rhs.begin(), rhs.end()); } return *this; } #endifν΄λμ€ λΆλ³μ(class invariant)
- dataλ 첫λ²μ§Έ μμ, μλ€λ©΄ 0μ κ°μ§λ€.
- data<=avail<=limit
- μμ±λ μμλ [data, avail)μ λ²μμ μ‘΄μ¬
- μμ±λμ§ μμ μμλ [avail, limit)μ λ²μμ μ‘΄μ¬
~cpp template <class T> void Vec<T>::create() { data = avail = limit = 0; // λν΄νΈ μμ±μ μ΄κΈ° λλ¬Έμ ν¬μΈν°μ λν¬μΈν°λ₯Ό λ£μ΄μ λΉ κ°μ²΄μμ λνλΈλ€. } template <class T> void Vec<T>::create(size_type n, const T& val) { data = alloc.allocate(n); // μΈμλ‘ λ°μ λ§νΌμ 곡κ°μ ν λΉνλ€. limit = avail = data + n; // λμ κ°λ¦¬ν¨λ€. νμ¬λ‘μλ μ΄κΈ°νμ nκ°μ 곡κ°μ ν λΉνκΈ° λλ¬Έμ avail = limit μ΄λ€. std::uninitialized_fill(data, limit, val); // μμ§ μ΄κΈ°ν λμ§ μμ 곡κ°μ μ¬λ¬κ°μ κ°μ²΄λ₯Ό μ½μ ν΄μΌνκΈ° λλ¬Έμ λΉλ©€λ²ν¨μλ₯Ό μ΄μ©ν΄μ μ΄κΈ°ν μν¨λ€. } template <class T> void Vec<T>::create(const_iterator i, const_iterator j) { data = alloc.allocate(j - i); limit = avail = std::uninitialized_copy(i, j, data); }
μ£Όμμ μ°Έκ³ νκ³ μ΄ν΄νκΈ° λ°λ.
~cpp template <class T> void Vec<T>::uncreate() { if (data) { // destroy (in reverse order) the elements that were constructed iterator it = avail; while (it != data) alloc.destroy(--it); // return all the space that was allocated alloc.deallocate(data, limit - data); } // reset pointers to indicate that the `Vec' is empty again data = limit = avail = 0; }
μ΄κΈ°ν λμ΄μλ λ΄λΆμ μμλ€μ νλμ© destroyν¨μλ₯Ό μ΄μ©ν΄μ μλ©Έμν¨λ€.
κ·Έν ν λΉλ 곡κ°μ deallocate ν¨μλ₯Ό μ΄μ©ν΄μ λ©λͺ¨λ¦¬ 곡κ°μμμ ν΄μ μν¨λ€.
ν΄μ κ° λλ μ΄νμλ λ€μ λΉ λ°±ν°λ‘ λνλ΄κΈ°μν΄μ data, limit, avail μ μ΄κΈ°ν νλ€.
~cpp template <class T> void Vec<T>::grow() { // when growing, allocate twice as much space as currently in use size_type new_size = max(2 * (limit - data), ptrdiff_t(1)); // λΉμ΄μλ 벑ν°μΈ κ²½μ°μλ 1κ°λ§ ν λΉνλ€. // allocate new space and copy existing elements to the new space iterator new_data = alloc.allocate(new_size); iterator new_avail = std::uninitialized_copy(data, avail, new_data); // return the old space uncreate(); // reset pointers to point to the newly allocated space data = new_data; avail = new_avail; limit = data + new_size; } // assumes `avail' points at allocated, but uninitialized space template <class T> void Vec<T>::unchecked_append(const T& val) { alloc.construct(avail++, val); }
grow ν¨μλ νλ² νΈμΆν λ μ΄λ―Έ μλ 곡κ°μ 2λ°°λ₯Ό ν λΉμν€κΈ° λλ¬Έμ κ³μλ push_backλ‘ μΈν λ©λͺ¨λ¦¬ ν λΉ μ€λ²ν€λλ₯Ό μ€μΌ μ μλ€.
unchecked_append()ν¨μλ grow() ν¨μμ λ°λ‘ λ€μμλ§ λμνλλ‘ κ΅¬μ±νκΈ° λλ¬Έμ λμμ μμ μ±μ 보μ₯ν μ μλ€. (λ¬Όλ‘ λ¬Έμλ‘ λ¨κ²¨μ μ΄ν ν΄λμ€ νμ₯μ λ€λ₯Έ νλ‘κ·Έλλ¨Έκ° μ μ μλλ‘ ν΄μΌν λ―)