<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>hubring</title>
    <link>https://hubring.tistory.com/</link>
    <description>일상 및 개발 블로그</description>
    <language>ko</language>
    <pubDate>Wed, 8 Jul 2026 18:12:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Hubring</managingEditor>
    <image>
      <title>hubring</title>
      <url>https://tistory1.daumcdn.net/tistory/3046046/attach/f5146c9a7c214013b8c9c8cbc008e036</url>
      <link>https://hubring.tistory.com</link>
    </image>
    <item>
      <title>CKA 시험 후기</title>
      <link>https://hubring.tistory.com/76</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;CKA 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Certified Kubernetes Administrator (CKA)의 약자로 Linux Foundation이 주관하는 쿠버네티스 관리자 인증 시험으로&lt;br /&gt;Kubernetes의 기본적인 기능들을 이해하고 사용할 수 있다면 합격이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 특징은 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;온라인 시험&lt;/li&gt;
&lt;li&gt;시험시간 2시간&lt;/li&gt;
&lt;li&gt;영어 문제&lt;/li&gt;
&lt;li&gt;VM 환경에서 kubernetes cli 기반의 실습형 시험&lt;/li&gt;
&lt;li&gt;공식 문서 오픈북 시험&lt;/li&gt;
&lt;li&gt;인증 유효기간 3년&lt;/li&gt;
&lt;li&gt;시험 신청 후 12개월 내 시험 가능&lt;/li&gt;
&lt;li&gt;1번의 재시험 가능&lt;/li&gt;
&lt;li&gt;PDF 인증서 및 디지털 배지 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험 신청&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 신청은 아래 링크에서 신청이 가능하다.&lt;br /&gt;&lt;a href=&quot;https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/&quot;&gt;https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byLKTk/btspkLyyGcS/33WiSbC9AQfWP1U36zuUM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byLKTk/btspkLyyGcS/33WiSbC9AQfWP1U36zuUM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byLKTk/btspkLyyGcS/33WiSbC9AQfWP1U36zuUM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyLKTk%2FbtspkLyyGcS%2F33WiSbC9AQfWP1U36zuUM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1352&quot; height=&quot;620&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;395달러로 50만원가까이한다...;&lt;br /&gt;굉장히 비싼 자격증으로 웬만하면 학교 or 회사를 통해 지원받아서 신청하자..&lt;br /&gt;(사실 직접 돈주고 시험보기엔 유효기간이 3년이라 좀 돈 아까운 시험으로 생각한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 팁으로 할인 쿠폰들이 구글에 &lt;code&gt;CKA 쿠폰&lt;/code&gt;이라고 검색하면 나오니 꼭 쿠폰을 먹이고 신청하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;213&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kB80j/btsph8nd78z/puKGzqzXbPsoLP2VKGgC2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kB80j/btsph8nd78z/puKGzqzXbPsoLP2VKGgC2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kB80j/btsph8nd78z/puKGzqzXbPsoLP2VKGgC2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkB80j%2Fbtsph8nd78z%2FpuKGzqzXbPsoLP2VKGgC2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;213&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;213&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;a href=&quot;https://scriptcrunch.com/linux-foundation-coupon/&quot;&gt;https://scriptcrunch.com/linux-foundation-coupon/&lt;/a&gt;&lt;br /&gt;여러개의 쿠폰들이 있을텐데 할인률이 큰것으로 적용하면된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험일 등록&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 신청이 끝났다면 시험일 등록이 가능하다.&lt;br /&gt;아마 가입했던 메일로 등록 url 올텐데 찾지 못한다면 아래 url을 통해 등록하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://trainingportal.linuxfoundation.org/learn/course/certified-kubernetes-administrator-cka/exam/exam&quot;&gt;https://trainingportal.linuxfoundation.org/learn/course/certified-kubernetes-administrator-cka/exam/exam&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험일은 거의 매일(주말 포함) 모든 시간대에서 내가 직접 선택할 수 있어 매우 편리하다.&lt;br /&gt;24시간 이전까지는 일정 변경이 가능하므로 부담없이 시험일을 정하자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험 준비&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 준비 기간은 쿠버네티스와 같은 오케스트레이션 플랫폼을 업무에 이미 사용하고 있는게 아니라면&lt;br /&gt;관련 구조 및 기능에 대한 이해가 필요하므로 사람마다 다르겠지만.. 적어도 1~2달 정도는 공부가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천 강의&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests/&quot;&gt;Udemy : Certified Kubernetes Administrator (CKA) with Practice Tests&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자주 할인 이벤트를 하니 할인받아 구매하자. (시험 신청 시 묶어서 구매할 수 도 있음)&lt;/li&gt;
&lt;li&gt;시간이 있다면 강의듣는 것을 추천하지만, 시험 합격을 위해서 강의를 모두 들을 필요는 없다.&lt;/li&gt;
&lt;li&gt;단 시험과 유사한 문제를 제공하니 Practice Test, Mock Exam 문제들은 꼭 풀어보자&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=6n5obRKsCRQ&amp;amp;list=PLApuRlvrZKohaBHvXAOhUD-RxD0uQ3z0c&quot;&gt;[따배쿠] 쿠버네티스 시리즈&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따배쿠 시리즈를 통해 쿠버네티스의 전반적인 기능들을 배울 수 있다.&lt;/li&gt;
&lt;li&gt;유데미 강의는 영어고 용어도 생소하다보니 이해가 어려운 경우가 있는데 관련된 내용을 따배쿠에서 찾아 들으면 이해하기 쉽다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=KdATmTulf7s&amp;amp;list=PLApuRlvrZKojqx9-wIvWP3MPtgy2B372f&quot;&gt;[따배씨] CKA 시리즈&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA 시험에 나오는 모든 유형들을 소개해 준다.&lt;/li&gt;
&lt;li&gt;하지만 강의가 유료기도 해서... 꼭 모두 들을 필요는 없으나 무료인 CKA 소개 내용은 봐두면 좋을 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천 책&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://search.shopping.naver.com/book/catalog/32444055567?cat_id=50005561&amp;amp;frm=PBOKPRO&amp;amp;query=%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4+%EC%9D%B8+%EC%95%A1%EC%85%98&amp;amp;NaPm=ct%3Dlko4w2rk%7Cci%3De54bfa8fd009d9238f3fbceb6b0594b9150ea789%7Ctr%3Dboknx%7Csn%3D95694%7Chk%3D07f257ed15bf8df04ca0a4b9348a4483e96a5c5e&quot;&gt;쿠버네티스 인 액션&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쿠버네티스 바이블과 같은 책, 실무에 사용한다면 꼭 사야한다고 생각한다.&lt;/li&gt;
&lt;li&gt;어쩌다 보니 쿠버네티스 책만 3권인데.. 이 책만 주로 보게 될 것 같다.&lt;/li&gt;
&lt;li&gt;강의를 들으면서 추가 설명이 필요할 때 보면 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험 유형&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;총 15 ~ 20 문제 (나의 경우 17문제가 나왔음)&lt;/li&gt;
&lt;li&gt;시험 시간 : 2시간&lt;/li&gt;
&lt;li&gt;합격 라인 : 66점&lt;/li&gt;
&lt;li&gt;시험 유형 : Udemy의 Lightning Labs와 Mock Exam에 문제들과 거의 유사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(중요) 시험이 며칠 안남은 상태라면... 유데미 목업 시험을 여러번 보고 시험 유형에 익숙해지도록 하자.&lt;br /&gt;오픈북 시험이니 문제를 풀면서 해당 유형이 공식 문서 어디서 나왔는지 미리 암기하면 좋다.&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기출 문제 (2023.07 기준)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;service account/ cluster role/ cluster role binding&lt;/li&gt;
&lt;li&gt;kubeadm 업그레이드 (노드 drain, uncordon 잊지말자)&lt;/li&gt;
&lt;li&gt;deployment 생성&lt;/li&gt;
&lt;li&gt;deployment scale up&lt;/li&gt;
&lt;li&gt;사이드카 컨테이너 파드 생성&lt;/li&gt;
&lt;li&gt;ETCD 백업 및 복구&lt;/li&gt;
&lt;li&gt;Service 생성&lt;/li&gt;
&lt;li&gt;멀티 컨테이너 파드 생성&lt;/li&gt;
&lt;li&gt;특정 네임스페이스의 파드만 허용하는 인그레이스 생성&lt;/li&gt;
&lt;li&gt;CPU 사용량이 가장 높은 파드 찾기&lt;/li&gt;
&lt;li&gt;PV&amp;amp;PVC 생성하기&lt;/li&gt;
&lt;li&gt;스케줄 가능한 노드와 taint 안걸린 노드 찾기&lt;/li&gt;
&lt;li&gt;특정 노드에 파드 실행시키기&lt;/li&gt;
&lt;li&gt;PVC request 증량하기&lt;/li&gt;
&lt;li&gt;trouble shooting 죽은 노드 복구하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 점수가 낮은게 4점 (명령어 한두줄로 끝나는 문제)&lt;br /&gt;중간이 7점 (명령어가 몇번 있고 살짝 번거로운? 작업 필요)&lt;br /&gt;가장 높은 점수 13점이 trouble shooting에서 나온다. &amp;lt;= 안전하게 합격하려면 꼭 풀자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험 당일&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보다 자세하고 정확한 내용은 &lt;a href=&quot;https://docs.linuxfoundation.org/tc-docs/certification/tips-cka-and-ckad&quot;&gt;공식 가이드&lt;/a&gt;를 확인해주세요!.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시험 공간&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 공간은 주변에 컴퓨터, 모니터, 키보드, 마우스, 웹캠, 충전기 필수적인 것을 제외하고 없어야한다.&lt;br /&gt;노트북으로 시험을 본다면 모니터를 사용할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책, 종이나 펜, 화이트보드, 물컵 등 모두 안되니 주의하자.&lt;br /&gt;(핸드폰 등 허용되지 않는 물품이 있다면 손이 닿지 않는 곳에 두고 감독관에게 확인시켜야 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누가 들어오거나 소음도 없어야하므로 되도록 방이 아닌 혼자 있을 수 있는 독서실이나 회의실에서 시험을 보는게 좋다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시험 준비물&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신분증을 잊지말자!&lt;br /&gt;주민등록증, 운전면허증도 가능하다곤 하는데 감독관이 외국인이다보니... 여권을 꼭 챙기는게 좋다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험 환경&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 환경은 아래 이미지와 같이 원격 VM 환경에서 진행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1315&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WFslO/btsppHOWgfc/i4KUMpkk018oJKa5t82r3K/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WFslO/btsppHOWgfc/i4KUMpkk018oJKa5t82r3K/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WFslO/btsppHOWgfc/i4KUMpkk018oJKa5t82r3K/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWFslO%2FbtsppHOWgfc%2Fi4KUMpkk018oJKa5t82r3K%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1315&quot; height=&quot;718&quot; data-origin-width=&quot;1315&quot; data-origin-height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 영역은 문제가 나오고 오른쪽이 VM 환경 화면으로 터미널을 실행해서 문제를 풀면 된다.&lt;br /&gt;시험 환경을 체감해보고 싶다면 &lt;a href=&quot;https://killer.sh/&quot;&gt;killer.sh&lt;/a&gt;를 통해 느낄 수 있다...&lt;br /&gt;(killer.sh에 나오는 문제는 실제 문제 난이도보다 훨씬 어렵다.. 문제 푸는건 비추)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제 영역&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 문제마다 관련 공식 문서 링크를 공유해준다.&lt;br /&gt;(하지만 검색해서 보는게 더 빠르다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 못풀겠다 싶으면 플래그 처리가 가능하니 플래그 후 다음 문제로 넘어가면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;! 각 문제마다 context 환경이 다르므로 문제에서 제공해주는 &lt;code&gt;kubectl config set-context &amp;lt;컨텍스트명&amp;gt;&lt;/code&gt; 명령어를 입력해서 꼭 환경을 변경해주자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;VM 환경&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;os 환경은 시험 등록 시 우분투나 centos 선택이 가능했던걸로 기억한다.&lt;br /&gt;환경이 굉장히 열악하고.. 네트워크가 매우 느리다..&lt;br /&gt;키보드도 조심조심? 눌러야한다. &lt;code&gt;a&lt;/code&gt;를 잘못해서 꾹 누르면 &lt;code&gt;aaaaaaaaaaaaa&lt;/code&gt; 가 입력된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;터미널&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl&lt;/code&gt; 자동완성과 k alias 는 셋팅되어 있다.&lt;br /&gt;편의를 위해 &lt;code&gt;jq&lt;/code&gt;, &lt;code&gt;tmux&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;man&lt;/code&gt; 도구도 설치되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널 복사 붙여 넣기는 Linux 키보드 단축키를 이용해야한다.&lt;br /&gt;Copy = Ctrl+SHIFT+C&lt;br /&gt;Paste = Ctrl+SHIFT+V&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널이 아닌 브라우저 검색이나 메모장 검색은 아래 단축키를 사용해야한다.&lt;br /&gt;Copy = Ctrl+C&lt;br /&gt;Paste = Ctrl+V&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;브라우저&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Firefox 브라우저가 제공된다.&lt;br /&gt;Ctrl+F 사용 가능하므로 검색어를 통해 필요한 문서 내용을 찾자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번역 플로그인이 설치되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubernetes.io 검색이 가능하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;메모장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모는 터미널의 vi, VIM, MousePad(메모장과 비슷)이 사용가능하다.&lt;br /&gt;공식 문서에서 명령어나 yaml 설정을 복사 붙여넣기해서 수정하는데 사용하면 편리하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시험 종료&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 후 결과는 24시간이내 메일을 통해 전달한다.&lt;br /&gt;(주말에도 보내준다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 떨어졌다해도 한번의 재시험 기회가 있으니 포기하지 말자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두가 합격하길 바라며, 후기 마칩니다!&lt;/p&gt;</description>
      <category>Cloud</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/76</guid>
      <comments>https://hubring.tistory.com/76#entry76comment</comments>
      <pubDate>Sun, 30 Jul 2023 01:20:39 +0900</pubDate>
    </item>
    <item>
      <title>[EC++] 항목 48: 템플릿 메타 프로그래밍, 하지 않겠는가?</title>
      <link>https://hubring.tistory.com/73</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;항목 48: 템플릿 메타 프로그래밍, 하지 않겠는가?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;템플릿 메타프로그래밍(template metaprogramming: TMP)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;템플릿 메타프로그래밍 란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 도중에 실행되는 템플릿 기반의 프로그램을 작성하는 일.&lt;/li&gt;
&lt;li&gt;C++ 컴파일러가 실행시키는, C++로 만들어진 프로그램.&lt;/li&gt;
&lt;li&gt;TMP 프로그램이 실행을 마친 후에 그 결과로 나온 출력물(템플릿으로부터 인스턴스화된 C++ 소스코드)이 다시 보통의 컴파일 과정을 거치는 것.&lt;/li&gt;
&lt;li&gt;1990년 초 TMP개념이 발굴된 후 C++ 언어 및 표준라이브러리에 TMP를 용이하게 만드는 확장요소가 추가될 여지까지 생김.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TMP의 강점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TMP를 쓰면 다른 방법으로 까다롭거나 불가능한 일을 쉽게 할 수 있음&lt;/li&gt;
&lt;li&gt;C++ 컴파일이 진행되는 동안에 실행되기 때문에, 기존 작업을 런타임 영역에서 컴파일 타임 영역으로 전환할 수 있음.&lt;/li&gt;
&lt;li&gt;일반적인 프로그램 실행 도중에 잡혀 왔던 에러들을 컴파일 타임에 찾을 수 있다는 점&lt;/li&gt;
&lt;li&gt;TMP를 써서 만든 프로그램이 효율적일 여지가 많다는 점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 타임에 이미 수행하여 실행 코드가 작아지고 실행시간이 짧아지며 메모리도 적게 잡음 (대신 컴파일 타임이 길어짐)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;template&amp;lt;typename IterT, typename DistT&amp;gt;
void advance(IterT&amp;amp; iter, DistT d){
    if(iter가 임의 접근 반복자이다.){   //임의 접근 반복자에 대해서 
        iter += d;                     //반복자 산술 연산을 쓴다.
    }
    else{
        if(d &amp;gt;= 0) { while (d--) ++iter; } // 다른 종류의 반복자에 대해서는 
        else { while (d++) --iter; } //++ 혹은 -- 연산의 반복 호출을 사용
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://www.tcpschool.com/cpp/cpp_iterator_category&quot;&gt;반복자 종류&lt;/a&gt; 참고&lt;/li&gt;
&lt;li&gt;위는 STL의 &lt;a href=&quot;https://en.cppreference.com/w/cpp/iterator/advance&quot;&gt;advance&lt;/a&gt;와 유사한 코드이다.&lt;/li&gt;
&lt;li&gt;이 유사코드를 진짜 코드로 만들려면 아래 코드처럼 typeid를 쓸 수 있다. (지극히 밋밋한 c++ 적인 방법)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입 정보를 꺼내는 작업을 런타임에 하겠다는 의미이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;template&amp;lt;typename IterT, typename DistT&amp;gt;
void advance(IterT&amp;amp; iter, DistT d){
    if(typeid(typename std::iterator_traits&amp;lt;IterT&amp;gt;::iterator_catetory)==
    typeid(std::random_access_iterator_tag)){ //임의 접근 반복자에 대해서 
        iter += d;                     //반복자 산술 연산을 쓴다.
    }
    else{
        if(d &amp;gt;= 0) { while (d--) ++iter; } // 다른 종류의 반복자에 대해서는 
        else { while (d++) --iter; } //++ 혹은 -- 연산의 반복 호출을 사용
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항목 47에서 지적했듯이, 특성정보(traits)를 쓰는 방법보다 효율이 떨어진다.&lt;/li&gt;
&lt;li&gt;타입 점검 동작이 컴파일 도중이 아니라 런타임에 일어나기 때문이며&lt;/li&gt;
&lt;li&gt;런타임 타입 점검을 수행하는 코드는 어쩔 수 없이 실행 파일에 들어가야하기 때문이다.&lt;/li&gt;
&lt;li&gt;특성정보 방법이 TMP이기 때문에 타입에 따른 if...else 처리를 컴파일 타임에 할 수 있었던 것이다.&lt;/li&gt;
&lt;li&gt;typeid 방법은 성능 외에도 컴파일 문제를 일으킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;std::list&amp;lt;int&amp;gt;::iterator iter;
...
advance(iter, 10); // 10개 원소 만큼 앞으로 옮기려 하지만 컴파일이 안됨&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 코드를 컴파일러가 돌린다고 가정했을 때, 다음과 같은 advance가 생성될 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void advance(std::list&amp;lt;int&amp;gt;::iterator&amp;amp; iter, int d){
    if(typeid(typename std::iterator_traits&amp;lt;std::list&amp;lt;int&amp;gt;::iterator&amp;gt;::iterator_catetory)==
    typeid(std::random_access_iterator_tag)){ 
        iter += d;     // 에러!              
    }
    else{
        if(d &amp;gt;= 0) { while (d--) ++iter; } 
        else { while (d++) --iter; } 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;std::list::iterator&lt;/code&gt; 는 양방향 반복자이기 때문에 &lt;code&gt;+=&lt;/code&gt; 연산을 지원하지 못한다.&lt;/li&gt;
&lt;li&gt;하지만 지금은 &lt;code&gt;typeid&lt;/code&gt; 점검이 실패하기 때문에 &lt;code&gt;+=&lt;/code&gt; 줄까지도 실행될 수가 없다.&lt;/li&gt;
&lt;li&gt;모든 코드가 제대로 되어 있는지 확인하는 일은 컴파일러의 책무이고 &lt;code&gt;iter += d&lt;/code&gt; 부분은 &lt;code&gt;iter&lt;/code&gt;가 임의 접근 반복자가 아닌 한 컴파일되지 않을 것은 자명하다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;TMP를 썼다면 주어진 타입에 따른 코드가 별로로 함수로 분리될 것이고, 각각의 함수는 자신이 맡은 타입에 대한 연산만 수행할 것이다.&lt;/li&gt;
&lt;li&gt;TMP는 그 자체가 튜링 완전성을 갖고 있는 것으로 알려져 왔다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;범용 프로그래밍 언어처럼 어떤 것이든 계산할 수 있는 능력을 갖고 있다는 뜻이다.&lt;/li&gt;
&lt;li&gt;변수 선언도 되고, 루프도 실행할 수 있으며, 함수를 작성하고 호출하는 것까지도 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단 이런것들에 필요한 구문요소가 &quot;보통&quot;의 C++에서 쓰이는 구문요소들과 꽤나 다른 모습을 갖고 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;if...else 조건문을 나타내는 데는 템플릿 및 템플릿 특수화 버전을 사용한다.&lt;/li&gt;
&lt;li&gt;프로그래밍 언어 수준으로 보면 이런 방법은 TMP 어셈블리라고 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TMP용 라이브러리도 많이 있다. (부스트의 &lt;a href=&quot;https://www.boost.org/doc/libs/1_63_0/libs/mpl/doc/index.html&quot;&gt;MPL&lt;/a&gt;이 대표적 항목 55 참조)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TMP 동작 원리 예&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TMP의 동작 원리를 엿볼 수 있는 부분으로 루프가 있다.&lt;/li&gt;
&lt;li&gt;반복(iteration)의미의 진정한 루프는 없기 때문에 재귀(recursion)를 사용해서 루프의 효과를 낸다.&lt;/li&gt;
&lt;li&gt;단 이 재귀조차도 우리가 알고 있는 종류가 아니다.&lt;/li&gt;
&lt;li&gt;실제론 재귀 함수 호출을 만들지 않고 재귀식 템플릿 인스턴스화(recursive template instantiation)를 하기 때문이다.&lt;/li&gt;
&lt;li&gt;아래는 재귀 호출을 하는 기본적인 TMP 계승 계산방법이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;template&amp;lt;unsigned n&amp;gt;
struct Factorial { 
    enum { value = n * Factorial&amp;lt;n-1&amp;gt;::value };
};

template&amp;lt;&amp;gt;
struct Factorial&amp;lt;0&amp;gt; {
    enum { value = 1 };
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Factorial&amp;lt;n&amp;gt;::value&lt;/code&gt; 를 참조함으로 n의 계승을 바로 얻을 수 있다.&lt;/li&gt;
&lt;li&gt;이 코드에서 루프를 도는 위치는 템플릿 인스턴스인 &lt;code&gt;Factorial&amp;lt;n&amp;gt;&lt;/code&gt;의 내부에서 &lt;code&gt;Factorial&amp;lt;n-1&amp;gt;&lt;/code&gt;을 참조하는 곳이다.&lt;/li&gt;
&lt;li&gt;재귀를 끝내는 특수조건은 바로 &lt;code&gt;Factorial&amp;lt;0&amp;gt;&lt;/code&gt; 이다.&lt;/li&gt;
&lt;li&gt;Factorial 템플릿은 구조체 타입이 인스턴스화되도록 만들어져 있다. 그리고 이렇게 만들어진 구조체 안에는 value라는 이름의 TMP 변수가 선언이 되어 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이것은 항목 2에서 말한 나열자 둔갑술(enum hack)이 쓰인 것이다.&lt;/li&gt;
&lt;li&gt;재귀적으로 돌면서 템플릿 인스턴스화 버전마다 자체적으로 value의 사본을 갖게 되고 각각 value에는 만들어진 값이 담기게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Factorial 템플릿은 다음과 같이 사용하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int main(){
    std::cout &amp;lt;&amp;lt; Factorial&amp;lt;5&amp;gt;::value; // 런타임 계산 없이 출력
    std::cout &amp;lt;&amp;lt; Factorial&amp;lt;10&amp;gt;::value;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TMP 적용이 적합한 예&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;치수 단위(dimensional unit)의 정확성 확인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;과학 기술 분야의 응용프로그램에서 치수 단위(질량, 거리, 시간 등)가 똑바로 조합되어야하는 것이 최우선&lt;/li&gt;
&lt;li&gt;예를 들면 속도를 나타내는 변수에 질량을 나타내는 변수를 대입하면 에러&lt;/li&gt;
&lt;li&gt;TMP를 사용하면 프로그램 안에서 쓰이는 모든 치수 단위의 조합이 제대로 됐는지를 맞춰(컴파일 동안에) 볼 수 있다.&lt;/li&gt;
&lt;li&gt;선행 에러 탐지(early error detection)에 TMP를 써먹을 수 있는 사례이다.&lt;/li&gt;
&lt;li&gt;분수식 지수 표현이 지원이 된다. 이런 표현이 가능하려면 컴파일러가 확인할 수 있도록 컴파일 도중에 분수의 약분이 되어야한다. time^(1/2) 는 time^(4/8)과 똑같이 받아들여져야 한다는 점이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;행렬 연산의 최적화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;operator* 등의 어떤 연산자 함수는 연산 결과를 새로운 객체에 담당 반환해야한다고 항목 21에서 이야기 했으며&lt;/li&gt;
&lt;li&gt;항목 44를 보신 분은 squareMatrix클래스를 기억할 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt; typedef squareMatrix&amp;lt;double, 10000&amp;gt; BigMatrix;
 BigMatrix m1, m2, m3, m4, m5;
 ...
 BigMatrix result = m1 * m2 * m3 * m4 * m5; //행렬의 곱을 계산&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;곱셈 결과를 보통 방법으로 계산하려면 네 개의 임시 행렬이 생겨야 한다. (operator* 한번씩 호출할 때 반환 결과로 생성됨)&lt;/li&gt;
&lt;li&gt;행렬 원소들 사이에 곱셈을 해야하므로 네 개의 루프가 순차적으로 만들어질 수 밖에 없다.&lt;/li&gt;
&lt;li&gt;이런 비싼 연산에 TMP를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;TMP를 응용한 고급 프로그래밍 기술인 표현식 템플릿(expression template)을 사용하면 덩치 큰 임시 객체를 없애는 것은 물론이고 루프까지 합쳐 버릴 수 있다.&lt;/li&gt;
&lt;li&gt;게다가 위에 써 놓은 사용자 코드에서 문법 하나 바꾸지 않고 적용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;맞춤식 디자인 패턴 구현의 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전략 패턴, 감시자 패턴, 방문자 패턴 등의 디자인 패턴은 그 구현 방법이 여러가지일 수 있다.&lt;/li&gt;
&lt;li&gt;TMP를 사용한 프로그래밍 기술인 정책 기반 설계(policy-based design)라는 것을 사용하면, 따로따로 마련된 설계상의 선택(정책)을 나타내는 템플릿을 만들어 낼 수 있게 된다.&lt;/li&gt;
&lt;li&gt;이렇게 만들어진 정책 템플릿은 임의대로 조합되어 사용자의 취향에 맞는 동작을 갖는 패턴으로 구현되는 데 쓰인다.&lt;/li&gt;
&lt;li&gt;예로 몇개의 스마트 포인터 동작 정책을 하나씩 구현한 각각의 템플릿을 만들어 두고, 이들을 사용자가 마음대로 조합하여 수백 가지의 스마트 포인터 타입을 생성할 수 있게 하는 것이다.&lt;/li&gt;
&lt;li&gt;생성식 프로그래밍(generative programming)의 기초가 바로 이 기술이다. (자동화된 코드 생성을 사용하는 프로그래밍 방식)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TMP 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문법이 비 직관적이고 개발도구의 지원도 아주 미약하다.(디버깅 불가능)&lt;/li&gt;
&lt;li&gt;비교적 최근 발견된 것으로 TMP의 프로그래밍 관례들도 아직 미약하다.&lt;/li&gt;
&lt;li&gt;그럼에도 불구하고 컴파일 타임에 수행하는 장점으로 매력이 있으며 점점 내외적 지원과 관련 서적들이 늘어가고 있다.&lt;/li&gt;
&lt;li&gt;특히 라이브러리 개발자라면 알아야할 프로그래밍이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이것만은 잊지 말자&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;템플릿 메타프로그래밍은 기존 작업을 런타임에서 컴파일 타임으로 전환하는 효과를 낸다.&lt;/li&gt;
&lt;li&gt;따라서 선행 에러 탐지와 높은 런타임 효과를 줄 수 있다.&lt;/li&gt;
&lt;li&gt;정책 선택의 조합에 기반하여 사용자 정의 코드를 생성하는 데 쓸 수 있으며, 또한 특정 타입에 대해 부적절한 코드가 만들어지는 것을 막는 데도 쓸 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;001&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/001.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/001.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>C++/Effective C++</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/73</guid>
      <comments>https://hubring.tistory.com/73#entry73comment</comments>
      <pubDate>Wed, 13 Oct 2021 01:07:44 +0900</pubDate>
    </item>
    <item>
      <title>[EC++] 항목 3 : 낌새만 보이면 const를 들이대 보자!</title>
      <link>https://hubring.tistory.com/72</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;const 큰 매력은 &lt;b&gt;“의미적인 제약”&lt;/b&gt;(외부 변경을 불가능하게 함)을 코드 수준에서 붙이며 컴파일러에서 이 제약을 지켜줄 수 있다는 점이다.&lt;br&gt;또한 클래스 바깥에서 전역 혹은 네임스페이스 유효범위의 상수를 &lt;b&gt;선언(정의)&lt;/b&gt;하는 데 쓸 수 있다.(항목 2 참조)&lt;br&gt;그 뿐아니라 파일, 함수, 블록 유효범위에서 static으로 선언한 객체에도 const를 붙일 수 있다.&lt;br&gt;클래스 내부의 경우에는, 정적 멤버 및 비정적 데이터 멤버 모두를 상수로 선언할 수 있다.&lt;br&gt;&lt;br&gt;그렇다면 포인터의 경우는 어떨까?&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;const 포인터 사용 &lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;포인터를 상수 지정 방법은 아래 3가지이다.&lt;br&gt;1. 포인터 자체를 상수 : &lt;span style=&quot;background-color: #dddddd;&quot;&gt;char * const p&lt;/span&gt;&lt;br&gt;2. 포인터가 가리키는 데이터를 상수 : &lt;span style=&quot;background-color: #dddddd;&quot;&gt;const char *p&lt;/span&gt;&lt;br&gt;3. 둘 다 상수로 지정 : &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;const char * const p &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; char const * const p&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;STL 반복자는 포인터를 본뜬 것이기 때문에 기본적인 동작 원리가 T* 포인터와 흡사하다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어떤 반복자를 const로 선언하는 일은 포인터를 상수로 선언하는 것(T* const 포인터)과 같다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;반복자가 가리키는 대상은 변경하지 못하며 그 대상의 값은 변경이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  const std::vector&amp;lt;int&amp;gt;::iterator iter = vec.begin(); 
 &lt;br&gt;* iter = 10; // 대상의 값 변경 가능 
 &lt;br&gt;++iter; // 대상을 변경하는 것은 불가능 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 변경이 불가능한 대상 값(객체)를 가리키는 반복자(const T* 포인터)가 필요하다면 const_iterator 를 사용하면 된다&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  const std::vector&amp;lt;int&amp;gt;::const_iterator iter = vec.begin(); 
 &lt;br&gt;* iter = 10; // 대상의 값 변경하는 것은 불가능 
 &lt;br&gt;++iter; // 대상을 변경 가능 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;const 함수 선언에 사용 &lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;가장 강력한 const의 용도는 함수 선언에 쓸 경우이다.&lt;br&gt;함수 선언문에서 const는 반환 값, 매개변수, 멤버 함수 앞에 붙에 붙을 수 있고 함수 전체에 대해 const를 붙일 수 있다.&lt;br&gt;&lt;br&gt;함수 반환 값을 상수로 정해 주면, 사용자측의 에러 돌발 상황을 줄이는 효과를 줄 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class Rational {...}; 
 &lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;const&lt;/span&gt; Retional operator*(const Rational&amp;amp; lhs, const Rational&amp;amp; rhs); 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;위 예시에서 operator* 반환값을 상수 객체로 지정하지 않게 되면 아래와 같은 문제가 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  Rational a, b, c; 
 &lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;( a * b ) = c; // a*b 결과에 = 으로 c 값을 넣을 수 있음.&lt;/span&gt; 
 &lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;...&lt;/span&gt; 
 &lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;If( a * b = c ) ... // 개발자의 실수 비교를 원한 것이였으나 문법 위반에 걸리지 않음.&lt;/span&gt; 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;위 코드는 문법 위반에 걸리지 않아 문제가 될 수 있다.&lt;br&gt;따라서 operator*의 반환 값을 const로 지정해야 이런 경우를 미연에 막을 수 있다.&lt;br&gt;&lt;br&gt;const 매개변수에 대해선 const 타입의 지역 객체와 특성이 동일하다.&lt;br&gt;이 기능 역시 매개변수 혹은 지역 객체를 수정할 수 없게 하는 것이 목적이라면 const를 잊지않고 가능한 한 항상 사용하는 것이 좋다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;상수 멤버 함수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;멤버 함수에 붙는 const &lt;br&gt;=&amp;gt; 해당 멤버 함수가 상수 객체에 대해 호출될 함수이다.&lt;br&gt;&lt;br&gt;중요한 이유가 무엇일까?&lt;br&gt;&lt;br&gt;1. 클래스의 인터페이스를 이해야기 좋게 하기 위함&lt;br&gt;그 클래스로 만들어진 객체를 변경할 수 있는 함수는 무엇이고, 또 변경할 수 없는 함수는 무엇인가를 사용자 쪽에서 알고 있어야 한다.&lt;br&gt;&lt;br&gt;2. 이 키워드를 통해 상수 객체를 사용할 수 있게 하자는 것&lt;br&gt;C++ 실행 성능을 높이는 핵심 기법 중 하나가 객체 전달을 ‘상수 객체에 대한 참조자(reference-to-const)’로 진행하는 것이다.&lt;br&gt;이 기법을 제대로 사용하려면 상수 사앹로 전달된 객체를 조작할 수 있는 const 멤버 함수, 즉 상수 멤버 함수가 준비되어 있어야한다.&lt;br&gt;&lt;br&gt;const 키워드가 있고 없고의 차이만 있는 멤버 함수들은 오버로딩이 가능하다. (C++의 중요한 성질이므로 꼭 외워두자) &lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class TextBlock { 
 &lt;br&gt; public : 
 &lt;br&gt; const char&amp;amp; &lt;span style=&quot;color: #ee2323;&quot;&gt;operator[]&lt;/span&gt;(std::size_t position) &lt;span style=&quot;color: #ee2323;&quot;&gt;const. // 상수 객체에 대한 operator[]&lt;/span&gt; 
 &lt;br&gt; { return text[position]; } 
 &lt;br&gt; char&amp;amp; &lt;span style=&quot;color: #ee2323;&quot;&gt;operator[]&lt;/span&gt;(std::size_t position) // 비상수 객체에 대한 operator[] 
 &lt;br&gt; { return text[postion]; } 
 &lt;br&gt; private : 
 &lt;br&gt; std::string text; 
 &lt;br&gt;} 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;위 처럼 선언된 TextBlock의 operator[]는 다음과 같이 쓸 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  TextBlock td(“Hello”); 
 &lt;br&gt;std::cout &amp;lt;&amp;lt; tb[0]; // TextBlock::operator[]의 비상수 멤버를 호출 
 &lt;br&gt; 
 &lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;const&lt;/span&gt; TextBlock ctb(“World”); 
 &lt;br&gt;std::cout &amp;lt;&amp;lt; ctb[0]; // TextBlock::operator[]의 상수 멤버를 호출 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;실제 프로그램에서 상수 객체가 생기는 경우는 아래와 같다.&lt;br&gt;1. 상수 객체에 대한 포인터&lt;br&gt;2. 상수 객체에 대한 참조자로 객체가 전달될 때&lt;br&gt;&lt;br&gt;실제 예제&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  void print(&lt;span style=&quot;color: #ee2323;&quot;&gt;const&lt;/span&gt; TextBlock&amp;amp; ctb){ // 이 함수에서 ctb는 상수 객체로 쓰인다. 
 &lt;br&gt; std::cout &amp;lt;&amp;lt; ctb[0]; // TextBlock::operator[]의 상수 
 &lt;br&gt;… 
 &lt;br&gt;} 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;operator[]를 오버로드해서 각 버전마다 반환 타입을 다르게 가져갔기 때문에 TextBlock의 상수 객체와 비상수 객체의 쓰임새가 달라진다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  std::cout &amp;lt;&amp;lt; tb[0]; // 비상수 버전의 객체를 읽음 
 &lt;br&gt;tb[0] = ‘x’; // 비상수 버전의 객체를 씀 
 &lt;br&gt;std::cout &amp;lt;&amp;lt; ctb[0]; // 상수 버전의 객체를 읽음 
 &lt;br&gt;ctb[0] = ‘x’; // 상수 버전의 객체를 씀 =&amp;gt; 컴파일 에러 발생! 상수 버전의 객체는 쓰기가 안된다. 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;넷째줄에서 발생한 에러는 operator[]의 반환 타입 때문에 생긴 것이다.&lt;br&gt;반환 타입 (const char&amp;amp;)에 대입 연산을 시도했기 때문이다.&lt;br&gt;&lt;br&gt;하나 더 눈여겨 볼 부분은 operator[]의 비상수 멤버는 char의 &lt;b&gt;참조자&lt;/b&gt;를 반환한다는 것이다.&lt;br&gt;만약 참조자를 반환하지 않는다면 아래 문장이 컴파일되지 않는다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  tb[0] = ‘x’; 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;왜 그럴까? 기본제공 타입을 반환하는 함수의 반환 값을 수정하는 일은 절대로 있을 수 없기 때문이다.&lt;br&gt;이는 C++ 성질 중 ‘&lt;b&gt;값에 의한 반환&lt;/b&gt;’을 수행하기 때문이다.&lt;br&gt;즉 수정된 값은 tb.text[0]의 &lt;b&gt;사본&lt;/b&gt;이지 그 자체는 아니다.&lt;br&gt;&lt;br&gt;&lt;b&gt;어떤 멤버 함수가 상수 멤버(const)&lt;/b&gt;라는 것이 대체 어떤 의미일까?&lt;br&gt;여기에는 굵직한 양대 개념이 있다. 비트수준 상수성과 논리적 상수성이다.&lt;br&gt;&lt;br&gt;&lt;b&gt;1. 비트수준 상수성( bitwise constness ,다른말로 물리적 상수성 physical constness)&lt;/b&gt;&lt;br&gt;비트 수준의 상수성은 어떤 멤버 함수가 그 객체의 어떤 데이터 멤버도 건드리지 않아야(정적 멤버는 제외) 그 멤버 함수가 const임을 인정하는 개념&lt;br&gt;즉, 객체를 구성하는 비트들 중 어떤 것도 바꾸면 안 된다는 것이다.&lt;br&gt;이를 이용하면 상수성 위반을 발견하는 데 어렵지 않다. 컴파일러는 데이터 멤버에 대해 대입 연산이 수행되었는지만 보면 된다.&lt;br&gt;(C++에서 정의하고 있는 상수성이 비트수준 상수성이다)&lt;br&gt;&lt;br&gt;그러나, 제대로 const로 동작하지 않는데도 이 비트수준 상수성 검사를 통과하는 멤버 함수들이 적지 않다.&lt;br&gt;포인터가 가리키는 대상을 수정하는 멤버 함수들이 이런 경우에 속한다.&lt;br&gt;이 함수는 비트수준 상수성을 갖는 것으로 판별되고 컴파일러도 불평하지 않는다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class CTextBlock { 
 &lt;br&gt; public : 
 &lt;br&gt; char&amp;amp; operator[](std::size_t position) &lt;span style=&quot;color: #ee2323;&quot;&gt;const &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;// 부적절한(그러나 비트수준 상수성에 있어서 허용되는) operator[] 선언&lt;/span&gt; 
 &lt;br&gt; { return pText[postion]; } 
 &lt;br&gt; private : 
 &lt;br&gt; char *pText; 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;코드에 나와 있듯이 operator[] 함수가 상수 멤버 함수로 선언되어 있음.&lt;br&gt;그럼에도 불구하고 해당 객체의 내부 데이터에 대한 참조자를 반환한다.(관련 항목 28 참조)&lt;br&gt;&lt;br&gt;operator[]의 내부 코드만 보면 pText는 안 건드리는 점은 확실하다, 그러니 컴파일러가 이 코드에 대해 불평하지 않는다.&lt;br&gt;하지만 이로 인해 아래와 같은 사태가 발생 할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  const CTextBlock cctb(“Hello”); // 상수 객체를 선언 
 &lt;br&gt;char *pc = &amp;amp;cctb[0]; // 상수 버전의 operator[]를 호출하여 cctb의 내부 데이터에 대한 포인터를 얻는다. 
 &lt;br&gt;*pc = ‘J’; //cctb는 이제 “Jello”라는 값을 갖는다. 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;어떤 값으로 초기화된 상수 객체를 하나 만들어 놓고 이것에다 상수 멤버 함수를 호출했더니 값이 변해버린 것이다.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;2. 논리적 상수성(logical constness)&lt;/b&gt;&lt;br&gt;논리적 상수성이란 개념은 이런 황당한 상황을 보완하는 대체 개념으로 나오게 되었다.&lt;br&gt;상수 멤버 함수라고 하여 객체의 한 비트도 수정할 수 없는 것이 아니라 일부 몇 비트 정도는 바꿀 수 있되, 그것을 사용자 측에서 알아채지 못하게만 하면 상수 자격이 있다는 것이다.&lt;br&gt;&lt;br&gt;CTextBlock 클래스는 문장 구역의 길이를 사용자들이 요구할 때마다 이 정보를 캐치해 둘 수 있을 텐데 다음과 같이 멤버를 둘 수 있을 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class CTextBlock { 
 &lt;br&gt; public: 
 &lt;br&gt; std::size_t length() const; 
 &lt;br&gt; private: 
 &lt;br&gt; char *pText; 
 &lt;br&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;std::size_t textlength;&lt;/span&gt; // 바로 직전에 계산한 텍스트 길이 
 &lt;br&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;bool lengthIsValid;&lt;/span&gt; // 이 길이가 현재 유효한가 
 &lt;br&gt;}; 
 &lt;br&gt; 
 &lt;br&gt;std::size_t CTextBlock::length() const { 
 &lt;br&gt; if(!lengthIsValid){ 
 &lt;br&gt; textLength = std::strlen(pText); // 에러! 상수 멤버 함수 안에서는 textLength 및 lengthIsValid에 대입할 수 없다. 
 &lt;br&gt; lengthIsValid = true; 
 &lt;br&gt; } 
 &lt;br&gt; return textLength; 
 &lt;br&gt;} 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;length의 구현은 비트수준의 상수성과 멀리떨어져 있다.&lt;br&gt;textLength 및 lengthIsValid가 바뀔 수 있기 때문이다.&lt;br&gt;하지만 CTextBlock의 상수 객체에 대해서는 아무 문제가 없어야 할 것 같은 코드이다. 하지만 컴파일러는 에러를 쏟아낸다.&lt;br&gt;&lt;br&gt;이런 상황에서는 어떻게 해야할까? 해답은 단순하다.&lt;br&gt;const에 맞서는 C++의 mutable을 사용하는 것이다.&lt;br&gt;mutable은 비정적 데이터 멤버를 비트수순 상수성의 족쇄에서 풀어 주는 키워드이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class CTextBlock { 
 &lt;br&gt; public: 
 &lt;br&gt; std::size_t length() const; 
 &lt;br&gt; private: 
 &lt;br&gt; char *pText; 
 &lt;br&gt; mutable std::size_t textlength; // 이 데이터 멤버들은 어떤 순간에도 수정이 가능하다. 
 &lt;br&gt; mutable bool lengthIsValid; // 심지어 상수 멤버 함수 안에서도 수정할 수 있다. 
 &lt;br&gt;}; 
 &lt;br&gt; 
 &lt;br&gt;std::size_t CTextBlock::length() const { 
 &lt;br&gt; if(!lengthIsValid){ 
 &lt;br&gt; textLength = std::strlen(pText); // 이제 문제가 없이 실행된다. 
 &lt;br&gt; lengthIsValid = true; 
 &lt;br&gt; } 
 &lt;br&gt; return textLength; 
 &lt;br&gt;} 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;상수 멤버 및 비상수 멤버 함수에서 코드 중복 현상을 피하는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;mutable은 생각지도 않던 비트 수준 상수성 문제를 해결하는 괜찮은 방법이나 const에 관련된 골칫거리 전부를 말끔히 씻어내진 못한다.&lt;br&gt;또 다른 예를 들어 보자&lt;br&gt;TextBlock의 operator[] 함수가 지금은 특정 문자의 참조자만 반환하고 있지만, 이것 말고도 경계 검사나 접근 정보 로깅, 내부자료 무결성 검증도 못할리 없다.&lt;br&gt;&lt;br&gt;이런저런 코드를 모조리 operator[]의 상수/비상수 버전에 넣어버리면 어느덧 코드 판박이 괴물이 떡 하니 우리 앞에서 뒹굴고 있게 된다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends2&quot; data-emoticon-name=&quot;083&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends2/large/083.png&quot;&gt;
 &lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends2/large/083.png&quot; width=&quot;150&quot;&gt;
&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class TextBlock { 
 &lt;br&gt; public : 
 &lt;br&gt; const char&amp;amp; operator[] (std::size_t postion) const { 
 &lt;br&gt; …. // 경계 검사, 접근 데이터 로깅, 자료 무결성 검증 
 &lt;br&gt; return text[postion]; 
 &lt;br&gt; } 
 &lt;br&gt; char&amp;amp; operator[](std::size_t postion){ 
 &lt;br&gt; …. // 경계 검사, 접근 데이터 로깅, 자료 무결성 검증 
 &lt;br&gt; return text[postion]; 
 &lt;br&gt; } 
 &lt;br&gt; private : 
 &lt;br&gt; std::string text; 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;무서운 코드 중복이다.. 컴파일 시간, 유지보수, 코드 크기 부풀림 감당할 수 있겠습니까?&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;047&quot; data-emoticon-isanimation=&quot;true&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/047.gif&quot;&gt;
 &lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/047.gif&quot; width=&quot;150&quot;&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;경계 검사 등의 코드를 별도의 멤버 함수에 옮겨 두고 operator[]에서 호출하게 만들면 제법 괜찮을 것이라 생각하지만 그대로 코드 중복은 여전하다.&lt;br&gt;한 번만 구현해 두고 이것을 두번 사용하고 싶진 않은가? opertator[]의 양 버전 중 하나만 제대로 만들고 다른 버전은 이것을 호출하는 식으로 만들고 싶을 것이다.&lt;br&gt;Const 껍데기를 캐스팅으로 날리면 어떨까 하는 생각에 이르게 된다. 기본적으로 캐스팅은 통념적으로 썩 좋은 아이디어는 아니다. &lt;br&gt;&lt;br&gt;operator[]의 상수 버전은 비상수 버전과 비교해서 하는 일이 정확히 똑같다 다른 점이 있다면 반환 타입에 const 키워드가 덧붙어 있다는 것뿐이다.&lt;br&gt;따라서 캐스팅을 써서 반환 타입으로부터 const 껍데기를 없애더라도 안전하다.&lt;br&gt;왜냐하면 비상수 operator[] 함수를 호출하는 쪽이라면 그 호출부엔 비상수 객체가 우선적으로 들어 있을게 분명하기 때문이다.&lt;br&gt;&lt;br&gt;따라서 캐스팅이 필요하긴 하지만, 안전성도 유지하면서 코드 중복을 피하는 방법은 비상수 operator[]가 상수 버전을 호출하도록 구현하는 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
 class TextBlock {
 &lt;br&gt;&amp;nbsp;&amp;nbsp;public : 
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const char&amp;amp; operator[](std::size_t position) const {
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; …
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return text[position];
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;char&amp;amp; operator[](std::size_t position) {
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &lt;span style=&quot;color: #ee2323;&quot;&gt;const_cast&lt;/span&gt;&amp;lt;char&amp;amp;&amp;gt;(&lt;span style=&quot;color: #ee2323;&quot;&gt;static_cast&lt;/span&gt;&amp;lt;const TextBlock&amp;amp;&amp;gt;(*this)[position]);
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 &lt;br&gt;}
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;보다시피 캐스팅이 한 번이 아니라 두 번 되어 있다.&lt;br&gt;지금 해야 하는 일은 비상수 operator[]가 상수 버전을 호출하게 하는 것이다.&lt;br&gt;그런데 비상수 operator[] 속에서 그냥 operator[]라고 적으면 그 자신이 재귀적으로 호출될 것이다.&lt;br&gt;해서 차선책으로 *this의 타입 캐스팅을 사용하는 것이다. 캐스팅을 쓴 이유는 const가 붙어야 하기 때문이다.&lt;br&gt;&lt;br&gt;정리하면 두 개의 캐스팅의 &lt;b&gt;첫 번째 것은 *this에 const를 붙이는 캐스팅&lt;/b&gt;이고 &lt;b&gt;두 번째 것은 상수 operator[]의 반환 값에서 const를 떼어내는 캐스팅&lt;/b&gt;이다.&lt;br&gt;이런 구현은 문법이 조금 이상해보이나 이 기법(비상수 멤버 함수의 구현에 상수 멤버 쌍둥이를 사용하는 기법) 자체는 꼭 알아둘 가치가 있다.&lt;br&gt;&lt;br&gt;&lt;b&gt;참고&lt;/b&gt; &lt;br&gt;* const_cast : 객체의 상수성을 없애는 용도로 사용 (C++ 스타일의 캐스트는 이것밖에 없다.)&lt;br&gt;* static_cast : 암시적 반환을 강제로 진행할 때 사용한다. 흔히들 이루어지는 타입 변환을 거꾸로 수행하는 용도로 쓰임. 상수 객체를 비상수 객체로 캐스팅하는 데 이것을 쓸 수는 없다.&lt;br&gt;&lt;br&gt;추가로 앞의 방법을 뒤집어서 하는 쪽 (코드 중복 회피를 위해 상수 버전이 비상수 버전을 호출하게 만드는 것)도 생각할 수 있는데, 상수 멤버 함수는 해당 객체의 논리적인 상태를 바꾸지 않겠다고 컴파일러와 굳게 약속한 함수인 반면, 비상수 멤버 함수는 이런 약속을 하지 않기 때문이다.&lt;br&gt;즉, 어쩌다가 상수 멤버 함수가 비상수 멤버 함수를 호출하게 되면 수정하지 않겠다는 그 약속을 위반하게 될 가능성이 있다.&lt;br&gt;&lt;br&gt;실제로 상수 멤버 함수에서 비상수 멤버 함수를 호출하는 코드를 어떻게든 컴파일 하려면 const_cast를 적용해서 *this에 붙은 const를 떼어내야 하는데, 이게 온갖 재앙의 씨앗이다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;const는 참으로 대단한 축복이다. 포인터나 반복자에 대해서 그렇고, 포인터/반복자참조자가 가리키는 객체에 대해서도 그렇고, 함수의 매개변수 및 반환 타입에 대해서도 마찬가지며 지역 변구는 물론이고 멤버 함수에게까지 const는 매우 든든한 친구이다. 할 수 있다면 아끼지 않고 남발하는게 좋다!&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이것만은 잊지 말자!&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;* const를 붙여 선언하면 컴파일러가 사용상의 에러를 잡아내는 데 도움을 준다. const는 어떤 유효범위에 있는 객체에도 붙을 수 있으며, 함수 매개 변수 및 반환 타입에도 붙을 수 있으며, 멤버 함수에도 붙을 수 있다.&lt;br&gt;* 컴파일러 쪽에서 보면 비트수준 상수성을 지켜야 하지만, 개념적인(논리적인) 상수성을 사용해서 프로그래밍해야 한다.&lt;br&gt;* 상수 멤버 및 비상수 멤버 함수가 기능적으로 서로 똑같게 구현되어 있을 경우에는 코드 중복을 피하는 것이 좋은데, 이때 비상수 버전이 상수 버전을 호출하도록 한다.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;</description>
      <category>C++/Effective C++</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/72</guid>
      <comments>https://hubring.tistory.com/72#entry72comment</comments>
      <pubDate>Wed, 16 Jun 2021 01:14:15 +0900</pubDate>
    </item>
    <item>
      <title>[EC++] 항목 2 : #define을 쓰려거든 const, enum, inline을 떠올리자.</title>
      <link>https://hubring.tistory.com/71</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;해당 항목 제목을 &lt;i&gt;&lt;b&gt;가급적 선행 처리자보다 컴파일러를 더 가까이 하자 &lt;/b&gt;&lt;/i&gt;로 가는게 더 괜찮았을 것 같다고 책에서 말하고 있다.&lt;br&gt;(....지금 항목 제목이 더 잘 기억에 남을듯 하다.)&lt;/p&gt;
&lt;figure data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;016&quot; data-emoticon-isanimation=&quot;true&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/016.gif&quot;&gt;
 &lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/016.gif&quot; width=&quot;150&quot;&gt;
&lt;/figure&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;#define의 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;아래 코드를 썼다고 가정하자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  #define ASPECT_RATIO 1.653 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;코드를 눈으로 볼 때는 ASPECT_RATIO가 기호식 이름으로 보이나 컴파일러에게는 선행 처리자가 해당 기호를 사용한 코드를 숫자 상수로 바꾸어 버리기 때문에 이름이 아닌 숫자로 보게된다. &lt;br&gt;만약 숫자 상수로 대체된 코드에서 컴파일 에러가 발생하게 되면 기호식 이름으로 알려주는 것이 아닌 숫자로 보이게 되어 에러의 원인을 찾는데 어려울 수 있다.&lt;br&gt;이 문제는 기호식 디버거에서도 나타날 소지가 있다.&lt;br&gt;=&amp;gt; 추가 예로 만약 &lt;b&gt;#define TEST 100&lt;/b&gt; 같이 선언 하고 어디선가 &lt;b&gt;TB_TEST&lt;/b&gt; 와 같은 변수 코드를 사용했다 가정하면.. 의도치 않게 &lt;b&gt;TB_100&lt;/b&gt; 이라는 변수 이름으로 변경되는 걸 볼 수 있을 것이다... 생각보다 흔하게 발생할 수 있는 문제이다.&lt;/p&gt;
&lt;figure data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;034&quot; data-emoticon-isanimation=&quot;true&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/034.gif&quot;&gt;
 &lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/034.gif&quot; width=&quot;150&quot;&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;해결법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;이 문제의 해결법은 매크로 대신 상수를 쓰는 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  const double AspectRatio = 1.653; 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;상수 타입의 데이터이기 때문에 컴파일러에게도 기호로 보이며 기호 테이블에도 들어가게 된다.&lt;br&gt;게다가 예제처럼 상수가 부동소수점 실수 타입일 경우 컴파일을 거친 최종 코드의 크기가 #define을 썼을 때보다 작게 나올 수 있다.&lt;br&gt;&lt;br&gt;해당 이유는 매크로를 쓰면 코드에 ASPECT_RATIO 들어간 위치마다 선행 처리자에 의해 상수로 변경되면서 목적코드에 사본이 등장 횟수만큼 들어가게되고,&lt;br&gt;반면 상수 타입을 쓰면 아무리 여러번 사용하더라도 사본은 딱 한 개만 생기기 때문이다.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;#define을 상수로 교체 시 주의점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;1. 상수 포인터(constant pointer)를 정의하는 경우 &lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;상수 정의는 대개 헤더 파일에 넣는 것이 상례로 포인터는 꼭 const로 선언해야한다.&lt;br&gt;이와 아울러 포인터가 가리키는 대상까지 const로 선언해 주어야한다. (상세한건 항목3을 참고)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;const&lt;/b&gt;&lt;/span&gt; char * &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;const&lt;/b&gt;&lt;/span&gt; authorName = “Scott Meyers” 
&lt;/blockquote&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br&gt;2. 클래스 멤버로 상수를 정의하는 경우&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;즉 클래스 상수를 정의하는 경우, 어떤 상수의 유효범위를 클래스로 한정하고자 할 때 그 상수를 멤버로 만들어야 하는데...&lt;br&gt;그 상수의 사본 개수가 한 개를 넘지 못하게 하고 싶다면 &lt;b&gt;정적(static)&lt;/b&gt; 멤버로 만들어야 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class GamePlayer { 
 &lt;br&gt; private : 
 &lt;br&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;static const int Numturns = 5;&lt;/b&gt;&lt;/span&gt; // 상수 선언 
 &lt;br&gt;} 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;Numturns는 정의된 것이 아닌 &lt;b&gt;선언&lt;/b&gt;됨.&lt;br&gt;정적 멤버로 만들어지는 정수류(char, bool 등) 타입의 클래스 내부 상수는 이들에 대해 주소를 취하지 않는 한, 정의 없이 선언만 해도 문제가 없다.&lt;br&gt;단, 클래스 상수의 주소를 구한다든지, 사용하고 있는 컴파일러가 정의를 달라고 하는 경우 별도의 정의를 제공해야 한다.&lt;br&gt;&lt;br&gt;아래가 그 예시이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  const int GamePlayer::NumTurns;&amp;nbsp;&amp;nbsp;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;클래스 상수의 정의는 헤더 파일이 아닌 &lt;b&gt;구현 파일&lt;/b&gt;에 둔다.&lt;br&gt;해당 정의에는 초기값이 있으면 안된다. =&amp;gt; 클래스 상수의 초기값은 해당 상수가 선언된 시점에서 바로 주어지기 때문이다.&lt;br&gt;&lt;br&gt;참고로 #define은 유효범위라는게 없어 클래스 상수로 만드는 것 자체가 불가능하며 어떤 형태의 캡슐화 혜택도 받을 수 없다.&lt;br&gt;&lt;br&gt;만약 오래된 컴파일러를 사용하여 위 문법이 받아들여지지 않는 경우, 초기값을 상수 &lt;u&gt;&lt;i&gt;&lt;b&gt;정의 &lt;/b&gt;&lt;/i&gt;&lt;/u&gt;시점에 주도록한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
 class CostEstimate {
 &lt;br&gt;&amp;nbsp;&amp;nbsp;private :
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;static const double FudgeFactor; // 정적 클래스 상수의 선언 (헤더 파일에 둔다)&lt;/span&gt;
 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...
 &lt;br&gt;};
 &lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;const double CostEstimate::FudgeFactor = 1.35; // 정적 클래스 상수의 정의 (구현 파일에 둔다)&lt;/span&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;웬만한 경우 이것으로 충분하지만 예외가 있다면 해당 클래스를 컴파일하는 도중에 클래스 상수의 값이 필요할 때이다.&lt;br&gt;예를 들어 GamePlayer::scores 등의 배열 멤버를 선언할 때가 대표적이다.&lt;br&gt;이 경우 구식 컴파일러를 사용한다면 &lt;i&gt;&lt;b&gt;나열자 둔갑술(enum hack) &lt;/b&gt;&lt;/i&gt;기법을 생각하자.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;나열자 둔갑술&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;이 기법의 원리는 나열자(enumerator) 타입의 값은 int가 놓일 곳에서도 쓸 수 있다는 C++ 을 이용하는 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  class GamePlayer { 
 &lt;br&gt; private : 
 &lt;br&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;enum { NumTurns = 5 }; // 나열자 둔갑술 NumTurns를 5에 대한 기호식 이름으로 만듦&lt;/span&gt; 
 &lt;br&gt; Int socres[NumTurns]; 
 &lt;br&gt;} 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;나열자 둔갑술을 알아 두면 여러가지로 도움이 된다.&lt;br&gt;&lt;br&gt;&lt;b&gt;1. 나열자 둔갑술 동작 방식이 const 보다는 #define에 더 가깝다.&lt;/b&gt;&lt;br&gt;const에서 주소를 잡아낼 수 있으나 #define에서는 주소를 얻는 것은 맞지 않다. 이는 enum도 동일하다.&lt;br&gt;따라서 정수 상수를 가지고 다른 사람이 주소를 얻거나 참조자를 쓰도록 원하지 않는 다면 enum은 좋은 자물쇠가 될 수 있다.&lt;br&gt;또한 #define 처럼 쓸데없는 메모리 할당도 하지 않는다.&lt;br&gt;&lt;br&gt;&lt;b&gt;2. 상당히 많은 코드에서 이 기법을 사용중이며 템플릿 메타프로그래밍의 핵심 기법이다.&lt;/b&gt;&lt;br&gt;혹시 발견하면 쉽게 알아볼 수 있도록 눈에 익혀두자&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;#define의 또 다른 문제 &lt;b&gt;매크로 함수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;아래 예는 매크로 인자들 중 큰 것을 사용해서 어떤 함수 f() 를 호출하는 매크로이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  #define CALL_WITH_MAX(a, b) f( (a) &amp;gt; (b) ? (a) : (b) ) 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;이런 식의 매크로는 여러 단점들이 있다 한 예로 인자마다 반드시 괄호를 씌워주어야 한다.&lt;br&gt;그러나 해당 예를 처리한다 해도 아래와 같은 코드의 경우 문제가 발생할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  int a = 5, b = 0; 
 &lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;CALL_WITH_MAX(++a, b); // a가 두 번 증가함.&lt;/span&gt; 
 &lt;br&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;CALL_WITH_MAX(++a, b+10); // a가 한 번 증가함.&lt;/span&gt; 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;비교에 따라 처리한 결과가 어떤 것이냐에 따라 a의 증가값이 달라져 버린다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br&gt;해결법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;br&gt;인라인 함수에 대한 템플릿을 준비하는 것이다. (항목 30 참조)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
  template&amp;lt;typename T&amp;gt; 
 &lt;br&gt;Inline void callWithMax(const T&amp;amp; a, const T&amp;amp; b){ // T가 정확히 무엇인지 모르기 때문에 매개변수로 상수 객체 참조자를 사용 
 &lt;br&gt; f( a &amp;gt; b ? a : b ); 
 &lt;br&gt;} 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;이 함수는 템플릿이기 때문에 동일 계열 함수군(family of function)을 만들어낸다.&lt;br&gt;동일한 타입의 객체 두개를 인자로 받고 둘 중 큰 것을 f()에 넘겨서 호출하는 구조이다.&lt;br&gt;&lt;br&gt;이 방법은 위 #define 매크로 함수 문제를 해결해준다.&lt;br&gt;그뿐 아니라 진짜 함수이기 떄문에 유효범위 및 접근 규칙을 그대로 따라갈 수 있다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;const, enum, inline 유념하며 선행 처리자(특히 #define) 사용을 줄이자.&lt;br&gt;현실적으로 아직은 #include, #ifdef/#ifndef 를 현장에서 많이 사용하고 있어 완전히 없애는 건 불가능하나 기회가 될 때마다 없애도록 하자.&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;br&gt;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;이것만은 잊지 말자!&lt;/b&gt;&lt;/span&gt; &lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;* 단순한 상수를 쓸 때는, #define보다 const 객체 혹은 enum을 우선으로 생각하자.&lt;br&gt;* 함수처럼 쓰이는 매크로를 만들려면 #define 매크로보다 인라인 함수를 우선 생각하자.&lt;/p&gt;</description>
      <category>C++/Effective C++</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/71</guid>
      <comments>https://hubring.tistory.com/71#entry71comment</comments>
      <pubDate>Sat, 12 Jun 2021 00:46:07 +0900</pubDate>
    </item>
    <item>
      <title>[EC++] 항목1 C++를 언어들의 연합체로 바라보는 안목은 필수</title>
      <link>https://hubring.tistory.com/70</link>
      <description>&lt;figure data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;009&quot; data-emoticon-isanimation=&quot;true&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif&quot;&gt;
 &lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif&quot; width=&quot;150&quot;&gt;
&lt;/figure&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;C++ 프로그래밍 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;br&gt;오늘날의 C++은 다중패러다임 프로그래밍 언어(multipradigm programming language)라고 불린다.&lt;br&gt;절차적(procedural), 객체 지향(object-oriented), 함수식(functional), 일반화(generic), 메타(meta) 프로그래밍의 개념까지 지원한다. &lt;br&gt;각 지원하는 프로그래밍 마다 적절한 사용 규칙이 존재한다.&lt;br&gt;C++ 을 제대로 따라잡기 위해 여러 개의 하위 언어(4가지)에 대해 알아보고 각각의 프로그래밍 개념에 맞는 규칙을 적용할 수 있도록 하자.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;1. C&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;C++ 은 여전히 C를 기본으로 하고 있다.&lt;br&gt;따라서 C 언어 기능만 쏙 뽑아서 사용이 가능하다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;2. 객체 지향 개념&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;클래스(생성자와 소멸자), 캡슐화, 상속, 다향성, 가상 함수(동적 바인딩) 등의 개념을 포함한다.&lt;br&gt;객체 지향 설계의 규칙들 대부분이 그대로 드러맞는 부분이다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;3. 템플릿 C++&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;C++의 일반화 프로그래밍의 부분&lt;br&gt;템플릿의 영향력이 커지면서 완전히 새로운 프로그래밍 패러다임이 파생되었다.&lt;br&gt;이 패러다임은 템플릿 메타 프로그래밍(template metaprograming : TMP)이라 부른다. &lt;br&gt;=&amp;gt; 이부분은 항목48에서 전반적으로 다룰예정&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;4. STL&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;템플릿 라이브러리로 컨테이너, 반복자, 알고리즘, 함수 객체로 이루어졌다.&lt;br&gt;STL 나름의 독특한 사용 규약을 가지고 있으므로 프로그래밍 시 그 규약을 따라 한다.&lt;br&gt;&lt;br&gt;이 4가지 하위 언어들이 C++을 이루고 있다는 점을 새기며 효과적인 프로그램 개발을 위해 각 하위 언어 사용에 따라 전략을 바꾸며 사용하도록 한다.&lt;br&gt;&lt;br&gt;하위언어 사용에 따른 전략 변경 예로 &lt;br&gt;C 스타일로 사용하는 경우, &lt;i&gt;&lt;b&gt;값 전달이 참조 전달 보다 대개 효율이 더 좋다 &lt;/b&gt;&lt;/i&gt;라는 규칙이 통하지만.&lt;br&gt;객체 지향으로 사용하는 경우, 생성자/소멸자의 개념으로 상수 &lt;i&gt;&lt;b&gt;객체 참조자에 의한 전달(pass-by-reference-to-const) 방식&lt;/b&gt;&lt;/i&gt;이 더 좋은 효율을 보인다. &lt;br&gt;=&amp;gt; 해당 부분이 더 효율적이라 하는 이유는 객체를 매개변수와 같이 전달할 때 값 전달(복사 생성자 호출)로 받게되면 메모리가 추가로 차지하게 되기 때문인 것으로 보임. (항목 20 참고)&lt;br&gt;&lt;br&gt;이 현상은 템플릿 C++를 쓰게 될 때 특히 두드러지는데 그 이유는 템플릿에서는 객체의 타입조차 알 수 없기 때문이다.&lt;br&gt;하지만 STL에서는 반복자와 함수 객체가 C의 포인터를 이용하여 만들었기에 다시 값 전달에 대한 규칙이 더 힘이 있다.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;이것만은 잊지 말자!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;* C++를 사용한 효과적인 프로그래밍 규칙은 C++의 어떤 부분(사용하는 프로그래밍 개념, 하위 언어)를 사용하냐에 따라 달라진다.&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;047&quot; data-emoticon-isanimation=&quot;true&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/047.gif&quot;&gt;
 &lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/047.gif&quot; width=&quot;150&quot;&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;</description>
      <category>C++/Effective C++</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/70</guid>
      <comments>https://hubring.tistory.com/70#entry70comment</comments>
      <pubDate>Fri, 11 Jun 2021 23:48:51 +0900</pubDate>
    </item>
    <item>
      <title>[EC++] 독자 여러분 반갑습니다</title>
      <link>https://hubring.tistory.com/69</link>
      <description>&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Effective C++ 책의 목적&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;c++를 효과적으로 구사하는 방법&lt;br&gt;의도대로 동작하기 위한 지침과 조언을 모아둠.&lt;br&gt;구체적인 제안을 항목으로 55개를 묶어 소개함.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;내용 부류&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
 &lt;li&gt;일반적 설계 전략&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
 &lt;li&gt;C++ 언어적 특징 실전 세부 사항&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;br&gt;여러가지 선택과 의문점들&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
 &lt;li&gt;상속과 템플릿 사이에 선택해야 한다면?&lt;/li&gt;
 &lt;li&gt;public 상속과 private 상속 사이에 골라야 한다면?&lt;/li&gt;
 &lt;li&gt;private 상속과 클래스 합성 사이에서 어떻게 해야할까?&lt;/li&gt;
 &lt;li&gt;멤버 함수와 비 멤버 함수 중 하나를 선택할 경우에는?&lt;/li&gt;
 &lt;li&gt;값에 의한 전달과 참조에 의한 전달 중 무엇을 어떤 상황에서 집어야 할까?&lt;/li&gt;
 &lt;li&gt;대입 연산자는 어떤 타입을 반환해야 적당할까?&lt;/li&gt;
 &lt;li&gt;소멸자를 가상 함수로 만들어야 할 때는 언제일까?&lt;/li&gt;
 &lt;li&gt;충분한 메모리를 찾지 못했을 때 operator new는 어떻게 동작시켜야 할까?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;br&gt;———-&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;용어 설명&lt;/h3&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br&gt;선언(declaration)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;코드에 사용되는 어떤 대상의 이름과 타입을 컴파일러에게 알려 주는 것&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
 extern int x&amp;nbsp;&amp;nbsp;// 객체 선언
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;본 책에서는 기본제공 타입이여도 객체라는 용어를 사용한다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;시그니처(signature)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;모든 함수 선언문에는 함수의 매개변수 리스트와 반환 타입 나와 있으며 이것을 시그니처라고 한다.&lt;br&gt;공식적인 정의에서는 함수의 반환 타입을 제외하고 말하지만 이 책에서는 반환 타입도 시그니처의 일부로 본다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;정의(definition)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;선언에서 빠진 구체적인 세부사항을 컴파일러에게 제공하는 것&lt;br&gt;객체에게 정의란 컴파일러가 그 객체의 메모리를 마련해 놓은 부분&lt;br&gt;함수/함수 템플릿에 대한 정의는 코드 본문을 제공하는 것&lt;br&gt;클래스/클래스 템플릿의 경우 그 클래스 혹은 템플릿의 멤버를 넣어 준 결과&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;초기화(initialization)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;어떤 객체에 최초의 갓을 부여하는 과정&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;기본 생성자(default constructor)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;어떤 인자도 주어지지 않은 채로 호출 될 수 있는 생성자&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
 class B {
 &lt;br&gt; Public :
 &lt;br&gt;&amp;nbsp;&amp;nbsp; explicit B(int x = 0, bool b = true);
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;explicit로 선언된 생성자는 암시적인 타입 변환을 수행하는 데 쓰이지 않게 됨 (타입 변환이 명시적인 곳은 사용가능)&lt;br&gt;이를 통해 예상하지 못했던 타입 변환을 막아준다. =&amp;gt; 생성자는 암시적 타입 사용할 이유가 없다면 해당 선언을 우선적으로 한다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;복사 생성자(copy constructor)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;어떤 객체의 초기화를 위해 그와 같은 타입의 객체로부터 초기화할 때 호출되는 함수&lt;br&gt;값에 의한 객체 전달을 정의해 주는 함수이기도 하다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;복사 대입 연산자(copy assignment operator)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;같은 타입의 다른 객체 어떤 객체의 값을 복사하는 용도로 쓰이는 함수&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
 Widget w1;
 &lt;br&gt;Widget w2(w1); // 복사 생성자 호출
 &lt;br&gt;w1 = w2; // 복사 대입 연산자 호출
 &lt;br&gt;Widget w3 = w2; // 복사 생성자 호출
&lt;/blockquote&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br&gt;STL&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;표준 템플릿 라이브러리 (Standard Template Library)의 준말&lt;br&gt;컨테이너 (vector, list, set, map ...), 반복자(vector&amp;lt;int&amp;gt;::iterator ..), 알고리즘(for_each, find, sort ...) 및 이들과 관련된 기능들의 결정체&lt;br&gt;컨테이너/반복자/알고리즘에 관련된 기능들이 상당 부분을 &lt;b&gt;함수 객체(function object) &lt;/b&gt;즉 함수처럼 도작하는 객체가 차지하고 있다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;미정의 동작(undefined behabior)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;동작 자체가 정의되어 있지 않는 상태, 실행 시간에 어떤 현상이 터질지 확실히 예측할 수 없다는 뜻&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
 Int *p = 0; // null&amp;nbsp;&amp;nbsp;포인터
 &lt;br&gt;std::cout &amp;lt;&amp;lt; *p; // 널포인터를 역참조하면 미정의 동작 발생
 &lt;br&gt;char name[] = “Darla”; 
 &lt;br&gt;char c = name[10]; // 유효하지 않은 배열 원소지정번호로 참조하면 미정의 동작 발생
&lt;/blockquote&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br&gt;인터페이스(interface)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;자바나 닷넷 계열의 언어의 경우 인터페이스라는 것이 언어 차원에서 주어져 있지만 C++ 에서는 없다.&lt;br&gt;이 책에 나오는 인터페이스는 함수의 시그니처 혹은 어떤 클래스의 접근 가능한 요소(public 인터페이스, protected 인터페이스)나 템플릿 타입 매개변수로서 유효해야 하는 표현식 등을 가리킨다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;사용자(client)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;코드를 사용하는 모든 대상&lt;br&gt;함수의 사용자라 하면 함수를 호출하는 코드, 그런 코드를 작성했거나 유지보수 하는 사람 모두 사용자&lt;br&gt;&lt;br&gt;————-&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;스레딩에 대한 고려사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;C++ 언어 차원에서 스레드에 대한 개념 자체가 없다. 어떤 종류의 병행성도 고려하지 않은 언어로 표준 라이브러리도 마찬가지이다.&lt;br&gt;이 책은 C++ 구문요소중 스레드 환경에서 문제를 일으킬 만한 것을 지적하여 알려주고 있다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;TR1 그리고 부스트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;TR1 (Technical Report 1) : C++ 표준 라이브러리에 새로 추가되는 기능들에 대한 명세&lt;br&gt;부스트 : C++ 라이브러리를 제공하는 단체 (http://boost.org)&lt;br&gt;&lt;br&gt;&lt;br&gt;—————&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;이 책의 원서는 2005년 5월에 나와 현재의 최신 C++ 버전과 맞지 않는 부분들이 있다.&lt;br&gt;TR1의 경우만 해도 C++11 에서 대부분의 제안 사항이 채택되어 포함되어 있으며 (std::tr1 으로 정의되어 있음) - &lt;a href=&quot;https://ko.m.wikipedia.org/wiki/C%2B%2B_%EA%B8%B0%EC%88%A0_%EB%B3%B4%EA%B3%A0%EC%84%9C_1&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;위키백과&lt;/span&gt;&lt;/a&gt; 참고&lt;br&gt;스레드 또한 C++11 에서 언어 차원에서 지원하고 있다. &lt;br&gt;&lt;br&gt;정리하면서 이상한 부분은 찾아보고 적어둘 예정이다.&lt;br&gt;&lt;br&gt;&lt;/p&gt;</description>
      <category>C++/Effective C++</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/69</guid>
      <comments>https://hubring.tistory.com/69#entry69comment</comments>
      <pubDate>Fri, 11 Jun 2021 00:40:05 +0900</pubDate>
    </item>
    <item>
      <title>NUMA</title>
      <link>https://hubring.tistory.com/68</link>
      <description>&lt;h1&gt;NUMA 아키텍처&lt;/h1&gt;
&lt;h2&gt;numa(Non-Uniform Memory Access)?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;불균형 메모리 접근&lt;/strong&gt;이라는 뜻&lt;/li&gt;
&lt;li&gt;멀티 프로세서 환경에서 적용되는 메모리 접근 방식&lt;/li&gt;
&lt;li&gt;UMA(Unifrom Memory Access) numa와 반대되는 개념&lt;ul&gt;
&lt;li&gt;해당 방식은 공용 BUS를 이용하여 메모리에 접근&lt;/li&gt;
&lt;li&gt;해당 방식의 문제는 0번 소켓에 있는 CPU가 메모리에 접근하는 동안 1번 소켓에 있는 CPU는 메모리에 접근 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UMA와 달리 로컬 메모리의 접근이 동시에 이워질 수 있음.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;하지만 로컬 메모리의 양이 모자라면 다른 CPU에 있는 메모리 접근이 필요하게됨&lt;br&gt;=&amp;gt; 메모리 접근 시간이 소요하여 성능 저하 발생.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;참고&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Local Access : 각각의 cpu마다 별도의 메모리가 있고 해당 메모리를 접근 하는 방식&lt;/li&gt;
&lt;li&gt;NODE : CPU+memory&lt;/li&gt;
&lt;li&gt;Remote Access : 자신의 메모리가 아닌 다른 노드의 메모리에 접근 (NUMA에서 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;리눅스에서 NUMA 확인&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ numaactl --show&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;numaactl은 numa와 관련된 정책을 확인하거나 설정할 때 사용&lt;/li&gt;
&lt;li&gt;기본 정책 &lt;code&gt;policy : default&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;관련된 메모리 할당 정책은 총 4가지이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;default&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;별도 설정이 없다면 모든 프로세스에 적용됨.&lt;/li&gt;
&lt;li&gt;현재 프로세스가 실행되고 있는 프로세서가 포함됨 노드에서 먼저 메모리를 할당 받아 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;bind&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;특정 프로세스를 특정 노드에 바인딩시키는 방식을 취함.&lt;/li&gt;
&lt;li&gt;이경우 메모리의 지역성이 좋아지기 때문에 메모리 접근 속도가 빨라서 성능이 좋아질 수 있음.&lt;/li&gt;
&lt;li&gt;단 바인드된 노드의 메모리가 부족하면 성능 하락&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;preferred&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;bind와 비슷하지만 선호하는 노드를 설정&lt;/li&gt;
&lt;li&gt;가능한 한 설정한 노드로부터 메모리를 할당 (bind 처럼 반드시는 아님)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;interleaved&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;다수의 노드에서 거의 동일한 비율로 메모리를 할당받음.&lt;/li&gt;
&lt;li&gt;Round-Robin 정책에 따라 다수의 노드로부터 한 번씩 돌아가면서 메모리를 할당 받음.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;$ numaactl --H&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;NUMA 노드가 몇개로 구성되어 있는지 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;각 노드의 cpu, size, free 정보를 보여준다.&lt;/li&gt;
&lt;li&gt;node distances 는 각 노드의 메모리 접근 시간을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;$ numastat -cm&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;numa 환경에서 현재 시스템에 할당된 메모리의 상태를 보여준다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;numa 아키텍처에서 메모리 불균형 상태를 확인할 수 있다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;전체 메모리에는 free 영역이 많이 있음에도 메모리 할당 정책에 따라 한쪽 노드에서 메모리 할당이 과하게 일어나면 swap을 사용하게 되며 이런 상태를 numastat를 통해서 확인이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;$ cat /proc/29800/numa_maps&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;numa_maps를 통해 메모리 할당 정책 확인&lt;/li&gt;
&lt;li&gt;/proc/&lt;pid&gt;/numa_maps 를 통해 해당 pid의 정책과 관련된 정보 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;관련글 링크&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://brunch.co.kr/@dreaminz/4&quot;&gt;https://brunch.co.kr/@dreaminz/4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>linux</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/68</guid>
      <comments>https://hubring.tistory.com/68#entry68comment</comments>
      <pubDate>Fri, 14 May 2021 18:26:31 +0900</pubDate>
    </item>
    <item>
      <title>Vim 사용방법 정리</title>
      <link>https://hubring.tistory.com/66</link>
      <description>&lt;h2&gt;저장 닫기&lt;/h2&gt;
&lt;p&gt;w : 저장&lt;br&gt;q : 닫기&lt;/p&gt;
&lt;h2&gt;상하좌우로 커서 이동&lt;/h2&gt;
&lt;p&gt;h :  오른쪽 이동&lt;br&gt;j  :  아래로 이동&lt;br&gt;k :  위로 이동&lt;br&gt;l : 왼쪽으로 이동&lt;/p&gt;
&lt;p&gt;숫자 + h/j/k/l : 숫자 만큼 이동&lt;/p&gt;
&lt;h2&gt;단어 단위로 이동&lt;/h2&gt;
&lt;p&gt;w : 정방향으로 단어 단위로 커서 이동&lt;br&gt;b : 역방향으로 단어 단위로 커서 이동&lt;/p&gt;
&lt;p&gt;W : 정방향으로 공백 단위로 이동&lt;br&gt;B : 역방향으로 공백 단위로 이동&lt;br&gt;e:&lt;/p&gt;
&lt;h2&gt;문장 단위로 이동&lt;/h2&gt;
&lt;p&gt;0 : 행의 맨 앞으로&lt;br&gt;$ : 행의 맨 뒤로&lt;br&gt;^ : 첫번째 글자로&lt;/p&gt;
&lt;p&gt;f/t+ 찾을 문자 : 찾을 문자의 위치로 이동&lt;br&gt;; : 다음것을 찾음.&lt;br&gt;F/T+찾을 문자 : 위로 찾음.&lt;/p&gt;
&lt;h2&gt;단어 검색하기&lt;/h2&gt;
&lt;p&gt;/ + 단어 : 검색할 단어 찾기&lt;br&gt;n : 정방향으로 이동&lt;br&gt;N : 역방향을 이동&lt;/p&gt;
&lt;p&gt;/asdf : 하이라이팅 끄기&lt;/p&gt;
&lt;p&gt;*: 커서 단어 검색&lt;/p&gt;
&lt;h2&gt;화면 스크롤 하기&lt;/h2&gt;
&lt;p&gt;Ctrl + e: 한줄씩 내려가기&lt;br&gt;Ctrl + y : 한줄씩 올라가기&lt;br&gt;ctrl + u : 반페이지 올리기&lt;br&gt;Ctrl + d : 반페이지 내리기&lt;/p&gt;
&lt;p&gt;gg : 문서의 첫행&lt;br&gt;G : 문서의 맨끝&lt;/p&gt;
&lt;p&gt;: 숫자 : 문서의 숫자 라인 위치&lt;/p&gt;
&lt;h2&gt;vim 세가지 모드&lt;/h2&gt;
&lt;p&gt;일반모드/입력모드/명령형모드&lt;br&gt;aio&lt;br&gt;AIO&lt;/p&gt;
&lt;h2&gt;입력하기&lt;/h2&gt;
&lt;p&gt;a: 커서 다음에서 입력모드&lt;br&gt;i: 현재 커서에서 입력모드&lt;br&gt;o: 다음 줄에서 입력모드&lt;br&gt;r : 현재 커서 리플레이스&lt;/p&gt;
&lt;p&gt;I : 행 맨 앞에서 입력모드&lt;br&gt;O : 앞 줄에서 입력모드&lt;/p&gt;
&lt;p&gt;Ctrl + [  : esc&lt;br&gt;ctrl+ h : 삭제 delete&lt;/p&gt;
&lt;h2&gt;삭제, 복사, 붙여넣기&lt;/h2&gt;
&lt;p&gt;x : 한글자 삭제&lt;br&gt;dd : 한 행 삭제&lt;br&gt;D : 현재 위치부터 끝까지&lt;br&gt;J : 밑에 줄을 위로 올려줌.&lt;/p&gt;
&lt;p&gt;p: 밑에다가 붙여넣기&lt;br&gt;P : 아래에 붙여넣기&lt;/p&gt;
&lt;h2&gt;작업 취소, 다시 실행, 이전 명령어 반복하기&lt;/h2&gt;
&lt;p&gt;u: 작업 취소&lt;br&gt;ctrl+r : 다시 redo&lt;br&gt;. : 이전 명령어 반복&lt;/p&gt;
&lt;h2&gt;비주얼 모드&lt;/h2&gt;
&lt;p&gt;v : 일반 비쥬얼 모드&lt;br&gt;V : 줄단위로 지정&lt;br&gt;Ctrl + v : 열단위로 지정&lt;br&gt;gg +v + G : 전체 지정&lt;/p&gt;
&lt;h2&gt;단어 선택하기&lt;/h2&gt;
&lt;p&gt;viw : visual in word 단어 선택&lt;br&gt;vi( : 소괄호 안에 있는 것을 선택&lt;br&gt;vi’ : ‘ 안에 있는 것을 선택&lt;br&gt;yiw : 바로 복사&lt;br&gt;ciw : 해당 당어를 삭제함과 동시에 입력모드&lt;/p&gt;
&lt;h2&gt;단어 바꾸기&lt;/h2&gt;
&lt;p&gt;빠른 방법&lt;br&gt;*+ciw+변경할 단어+ctrl[+n+.+n+.&lt;/p&gt;
&lt;p&gt;더 빠른 방법&lt;br&gt;:%s/찾을단어/변경단어/c : 하나씩 옮기며 변경&lt;br&gt;:%s/찾을단어/변경단어/g : 한꺼번에 단어 바꾸기&lt;/p&gt;
&lt;h2&gt;창 분할하기&lt;/h2&gt;
&lt;p&gt;:vs : 수직 분할&lt;br&gt;:sp : 수평 분할&lt;br&gt;Ctrl+ w + 방향키 : 윈도우 이동&lt;br&gt;:enew: 새창 띄우기&lt;/p&gt;
&lt;h2&gt;파일 다루기&lt;/h2&gt;
&lt;p&gt;:E : 현재 파일 위치에 댜른 파일 보기&lt;br&gt;:bn : buffer next 다음 버퍼로 이동&lt;br&gt;:bp : buffer previous 이전 버퍼로 이동&lt;br&gt;:b+숫자 : 숫자 버퍼로 이동&lt;br&gt;:bd : 버퍼 닫기&lt;/p&gt;
&lt;h2&gt;작업 자동화&lt;/h2&gt;
&lt;p&gt;qq: 작업 녹화&lt;br&gt;q: 작업 녹화 후 q  작업녹화 종료&lt;br&gt;@ : 작업 반복 실행&lt;br&gt;@@ : 두번 반복 실행&lt;br&gt;@@@@… : 여러번 반복 실행&lt;/p&gt;
&lt;h2&gt;vimrc 설정하기&lt;/h2&gt;
&lt;p&gt;set number relativenumber&lt;br&gt;set guifont=D2Coding:h36&lt;/p&gt;
&lt;h2&gt;Cheat Sheet&lt;/h2&gt;
&lt;p&gt;Vim 에디터의 주요 기능들을 정리된 이미지&lt;/p&gt;
&lt;p&gt;￼&lt;/p&gt;
&lt;h2&gt;vim Tutor&lt;/h2&gt;
&lt;p&gt;Vim 튜토리얼&lt;/p&gt;
&lt;p&gt;$vimtutor : 튜토리얼 파일 열기&lt;/p&gt;
&lt;h2&gt;vim Adventures&lt;/h2&gt;
&lt;p&gt;Vim 게임.&lt;br&gt;게임을 하면서 vim을 배움.&lt;/p&gt;
&lt;h2&gt;vim Golf&lt;/h2&gt;
&lt;p&gt;사용자들이 문제를 내고 적은 명령어로 해결.&lt;/p&gt;</description>
      <category>linux</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/66</guid>
      <comments>https://hubring.tistory.com/66#entry66comment</comments>
      <pubDate>Wed, 24 Mar 2021 23:39:25 +0900</pubDate>
    </item>
    <item>
      <title>Tmux 설치 및 사용법</title>
      <link>https://hubring.tistory.com/65</link>
      <description>&lt;h2&gt;tmux (Terminal Multiplexer)&lt;/h2&gt;
&lt;p&gt;tmux는 사용자가 단일 단말기 창 또는 원격 터미널 세션 안에서 여러 별도의 터미널 세션에 액세스할 수 있도록 여러 가상 콘솔을 다중화하는데 사용할 수 있는 응용 소프트웨어이다. 이 응용 프로그램은 명령어 인터페이스로부터 다수의 프로그램을 처리하고 유닉스 셸로부터 프로그램을 분리하는 데에 유용하다.[2] 이것은 GNU Screen과 동일한 기능을 많이 제공하지만 BSD 허가서로 배포된다.&lt;br&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/Tmux&quot;&gt;wiki 백과참고&lt;/a&gt; &lt;/p&gt;
&lt;h2&gt;tmux 설치&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Install Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Arch Linux&lt;/td&gt;
&lt;td&gt;pacman -S tmux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debian or Ubuntu&lt;/td&gt;
&lt;td&gt;apt install tmux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fedora&lt;/td&gt;
&lt;td&gt;dnf install tmux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RHEL or CentOS&lt;/td&gt;
&lt;td&gt;yum install tmux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS (using Homebrew)&lt;/td&gt;
&lt;td&gt;brew install tmux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS (using MacPorts)&lt;/td&gt;
&lt;td&gt;port install tmux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;openSUSE&lt;/td&gt;
&lt;td&gt;zypper install tmux&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tmux/tmux/wiki/Getting-Started&quot;&gt;https://github.com/tmux/tmux/wiki/Getting-Started&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;mac에서 brew가 없는 경우 설치 명령어&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/bin/bash -c &amp;quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Tmux 사용 방법.&lt;/h2&gt;
&lt;p&gt;참고 - &lt;a href=&quot;https://npd-58.tistory.com/21&quot;&gt;https://npd-58.tistory.com/21&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#새로운 session 생성
tmux new -s &amp;lt;session_name&amp;gt; -n &amp;lt;window_name&amp;gt;

#session 이름 수정
ctrl + b, $

#session 종료는 tmux에서 exit

#session 중단하기
ctrl + b, d

#session 목록 보기
tmux ls

#session 다시 시작
tmux attach -t &amp;lt;session-number or session-name&amp;gt;

#페이지 이동 
alt + up, down
#window 생성
ctrl + b, c

#window 이름 수정
ctrl + b, ,

#window 종료
ctrl + d

#window 이동
ctrl + b, 0-9 : window number
            n : next
            p : prev
            w : window selector
#pane 나누기
ctrl + b, % : 세로 분할
          &amp;quot; : 가로 분할

#pane 이동
ctrl + b, q : number
          o : 순서대로 이동

#pane 닫기
ctrl + d

#사이즈 조절
ctrl + b, :resize-pane -L,R,D,U 10
OR
ctrl + b, alt + 방향키

#레이아웃 변경
ctrl + b, spacebar&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;tmux.conf&lt;/h2&gt;
&lt;p&gt;~/.tmux.conf 파일을 생성해 설정을 저장해두면 시작할 때 자동으로 설정을 불러온다&lt;br&gt;필요한 설정들을 지정하면 보다 편리하게 사용이 가능하다.&lt;/p&gt;</description>
      <category>linux</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/65</guid>
      <comments>https://hubring.tistory.com/65#entry65comment</comments>
      <pubDate>Wed, 24 Mar 2021 14:39:04 +0900</pubDate>
    </item>
    <item>
      <title>Linux에서 쉘스크립트 파일 만들기</title>
      <link>https://hubring.tistory.com/64</link>
      <description>&lt;p&gt;리눅스에서 간편하게 실행 또는 설치 등의 목적으로 쉘 스크립트를 많이 사용하고 있다.&lt;br&gt;하지만 sh 파일을 만들고 바로 실행하려하면 권한 오류가 발생한다. 그 이유는 리눅스는 실행에 대한 권한이 따로 존재하기 때문디다.&lt;/p&gt;
&lt;h3&gt;.sh 파일 만들기&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;vi test.sh&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;실행&lt;/h3&gt;
&lt;p&gt;바로 실행하게 되면 아래와 같이 오류가 발생.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./test.sh
zsh: permission denied: ./test.sh&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;권한 주기&lt;/h3&gt;
&lt;p&gt;chmod를 사용하여 권한 부여 (+x는 executable 뜻이다)&lt;br&gt;&lt;code&gt;chmod +x test.sh&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;sh 파일 실행&lt;/h3&gt;
&lt;p&gt;실행방법은 여러가지 방법이 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./clear.sh
$ sh clear.sh
$ bash clear.sh
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>linux</category>
      <author>Hubring</author>
      <guid isPermaLink="true">https://hubring.tistory.com/64</guid>
      <comments>https://hubring.tistory.com/64#entry64comment</comments>
      <pubDate>Wed, 24 Mar 2021 13:31:12 +0900</pubDate>
    </item>
  </channel>
</rss>