<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Code Habit</title>
    <link>https://codereader37.tistory.com/</link>
    <description>필요한 코드를 정리한 개인 블로그입니다. </description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 01:25:41 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>코드베어</managingEditor>
    <item>
      <title>서버 네트워크 성능 측정하기</title>
      <link>https://codereader37.tistory.com/233</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 서버에서 네트워크를 점검할 때 많이 사용하는 iperf3와 네트워크 트래픽 측정 관련 shell을 정리해보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 툴이지만 실제 회사업무에서 서버 네트워크 상태를 체크하는데 유용하게 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. CentOS에 iperf3 설치하기&lt;/h3&gt;
&lt;pre id=&quot;code_1728723622977&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo dnf install iperf3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. iperf3 사용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;2.1 서버모드 실행&lt;/h4&gt;
&lt;pre id=&quot;code_1728724295157&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;iperf3 -s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;2.2 클라이언트 모드로 접속하기&lt;/h4&gt;
&lt;pre id=&quot;code_1728724348939&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;iperf3 -c server_ip&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2.3 결과 ( 클라이언트 모드 )&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2024-10-12 오후 6.09.07.png&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GHsmv/btsJ3r7arGY/LAj0O8fvYWgn3QEzA3Ldtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GHsmv/btsJ3r7arGY/LAj0O8fvYWgn3QEzA3Ldtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GHsmv/btsJ3r7arGY/LAj0O8fvYWgn3QEzA3Ldtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGHsmv%2FbtsJ3r7arGY%2FLAj0O8fvYWgn3QEzA3Ldtk%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;1274&quot; height=&quot;510&quot; data-filename=&quot;edited_edited_스크린샷 2024-10-12 오후 6.09.07.png&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server 역할을 수행할 서버에서 서버모드로 iperf3를 실행 후 타 서버에서 클라이언트 모드로 접속하면 위와 같이 초당 네트워크 전송량을 측정해준다. 전송량을 따로 명시하지 않으면 NIC카드가 허용하는 최대치까지 전송해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초당 전송량은 900MBytes정도며 Retr(재전송 횟수)는 평균적으로 0임을 알 수 있다. 참고로 재전송 횟수는 적을수록 안정적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 네트워크 트래픽 측정 쉘&lt;/h3&gt;
&lt;pre id=&quot;code_1728724420086&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;while true
do
    # 현재의 bytes 값을 읽어옴 (Receive와 Transmit)
    RX_BYTES_1=$(cat /proc/net/dev | grep $INTERFACE | awk '{print $2}')
    TX_BYTES_1=$(cat /proc/net/dev | grep $INTERFACE | awk '{print $10}')

    sleep 1  # 1초 동안 대기

    # 1초 후의 bytes 값을 읽어옴 (Receive와 Transmit)
    RX_BYTES_2=$(cat /proc/net/dev | grep $INTERFACE | awk '{print $2}')
    TX_BYTES_2=$(cat /proc/net/dev | grep $INTERFACE | awk '{print $10}')

    # 초당 전송량 계산 (바이트)
    RX_RATE=$((RX_BYTES_2 - RX_BYTES_1))
    TX_RATE=$((TX_BYTES_2 - TX_BYTES_1))

    # 바이트를 Mbps로 변환
    RX_Mbps=$(echo &quot;scale=2; $RX_RATE * 8 / 1000000&quot; | bc)
    TX_Mbps=$(echo &quot;scale=2; $TX_RATE * 8 / 1000000&quot; | bc)

    # 결과 출력
    echo &quot;RX: $RX_Mbps Mbps, TX: $TX_Mbps Mbps&quot;
done&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쉘을 실행하면 초당 네트워크 트래픽 ( RX / TX )를 측정할 수 있다.&amp;nbsp;&lt;/p&gt;</description>
      <category>CentOS</category>
      <category>iperf</category>
      <category>rx</category>
      <category>Shell</category>
      <category>tx</category>
      <category>네트워크</category>
      <category>리눅스</category>
      <category>서버</category>
      <category>측정</category>
      <category>트래픽</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/233</guid>
      <comments>https://codereader37.tistory.com/233#entry233comment</comments>
      <pubDate>Sat, 12 Oct 2024 18:20:23 +0900</pubDate>
    </item>
    <item>
      <title>C++ 에서 YAML 다루기 : yaml-cpp 시작하기</title>
      <link>https://codereader37.tistory.com/232</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;YAML 파일은 간결하고 직관적인 데이터 구조를 표현하는 형식으로 구성 파일에 주로 사용된다. yaml-cpp는 c++언어에서 yaml파일을 다룰 수 있는 강력한 라이브러리로, 다양한 yaml 기능을 지원하며 설치가 쉽고 사용이 간편하다. 이 글에서는 yaml-cpp의 기본적인 사용법을 단계별로 알아보겠다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. yaml-cpp 설치하기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 git code 다운, 빌드 &amp;amp; 설치&lt;/h4&gt;
&lt;pre id=&quot;code_1728569577729&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git clone https://github.com/jbeder/yaml-cpp.git

cd yaml-cpp
mkdir build
cd build
cmake ..
make
sudo make install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 CMakeLists.txt 파일에 yaml-cpp 라이브러리 추가&lt;/h4&gt;
&lt;pre id=&quot;code_1728569621266&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;find_package(yaml-cpp REQUIRED)
target_link_libraries(your_project_name yaml-cpp)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2 yaml-cpp 사용 예제&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 yaml 파일예제&lt;/h4&gt;
&lt;pre id=&quot;code_1728569932329&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;name: &quot;Example&quot;
version: 1.0
dependencies:
  - yaml-cpp
  - boost
  - fmt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2 yaml 사용예제 ( cpp )&lt;/h4&gt;
&lt;pre id=&quot;code_1728570055204&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;yaml-cpp/yaml.h&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;

int main() {
    YAML::Node config = YAML::LoadFile(&quot;example.yaml&quot;);

    // 단일 값 읽기
    std::string name = config[&quot;name&quot;].as&amp;lt;std::string&amp;gt;();
    double version = config[&quot;version&quot;].as&amp;lt;double&amp;gt;();

    // 배열 값 읽기
    for (auto dep : config[&quot;dependencies&quot;]) {
        std::cout &amp;lt;&amp;lt; &quot;Dependency: &quot; &amp;lt;&amp;lt; dep.as&amp;lt;std::string&amp;gt;() &amp;lt;&amp;lt; std::endl;
    }

    std::cout &amp;lt;&amp;lt; &quot;Name: &quot; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &quot;\nVersion: &quot; &amp;lt;&amp;lt; version &amp;lt;&amp;lt; std::endl;
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3 더 복잡한 구조 읽기&lt;/h4&gt;
&lt;pre id=&quot;code_1728570118078&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;person:
  name: &quot;John Doe&quot;
  age: 30
  address:
    street: &quot;1234 Main St&quot;
    city: &quot;Hometown&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1728570172355&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;YAML::Node person = config[&quot;person&quot;];
std::string name = person[&quot;name&quot;].as&amp;lt;std::string&amp;gt;();
int age = person[&quot;age&quot;].as&amp;lt;int&amp;gt;();
std::string street = person[&quot;address&quot;][&quot;street&quot;].as&amp;lt;std::string&amp;gt;();
std::string city = person[&quot;address&quot;][&quot;city&quot;].as&amp;lt;std::string&amp;gt;();&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CMake</category>
      <category>cpp</category>
      <category>yaml</category>
      <category>yaml-cpp</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/232</guid>
      <comments>https://codereader37.tistory.com/232#entry232comment</comments>
      <pubDate>Thu, 10 Oct 2024 23:24:25 +0900</pubDate>
    </item>
    <item>
      <title>[python] 간단한 http request client 구현</title>
      <link>https://codereader37.tistory.com/231</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회사 작업 중 서버를 Active/Pause 상태로 변환하는데 http 통신을 할 필요가 있어 파이썬으로 간단하게 구현해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요요구 사항과 구현된 프로그램 특징은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 프레임 크기에 따른 체크박스 자동 배치 ( 줄 바꿈 처리 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 성공/실패 여부 Text로 출력하면서 자동 스크롤 되는 debug 창 필요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 파이썬 기본 내장 라이브러리인 tkinter 사용하여 간단한 ui 구현 ( 체크박스, push 버튼, Debug Text 창 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 파이썬 requests 라이브러리 사용하여 http request 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717903363942&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import tkinter as tk
import requests
from dataclasses import dataclass
from tkinter import scrolledtext

@dataclass
class Address:
    host:str
    ip:str
    checked:bool

addresses = [
     Address(&quot;hostname_1&quot;, &quot;127.0.0.1&quot;, False),
     Address(&quot;hostname_2&quot;, &quot;127.0.0.1&quot;, False),
     Address(&quot;hostname_3&quot;, &quot;127.0.0.1&quot;, False),
     Address(&quot;hostname_4&quot;, &quot;127.0.0.1&quot;, False),
]

def on_connect_button_click():
    for addr in addresses:  
        if(addr.checked.get() == True):
            url = f&quot;http://{addr.ip}:8060/connect_request?key=server1&quot;
            if send_request_get(url) == False:
                add_debug_info(f&quot;Failed to Request Connect nats {addr.host}&quot;)
            else:
                add_debug_info(f&quot;Success to Request Connect nats {addr.host}&quot;)

def on_disconnect_button_click():
    for addr in addresses:
        if(addr.checked.get() == True):
            url = f&quot;http://{addr.ip}:8060/disconnect_request?key=server1&quot;
            if send_request_get(url) == False:
                add_debug_info(f&quot;Failed to Request Disconnect nats {addr.host}&quot;)
            else:
                add_debug_info(f&quot;Success to Request Disconnect nats {addr.host}&quot;)
                
def on_reset_button_click():
    for addr in addresses:
        addr.checked.set(False)

def send_request_get(url) -&amp;gt; bool:
    result = True
    try:
        response = requests.get(url)
        if response.status_code == 200:
            result = True
        else:
            result = False
    except requests.RequestException as e:
        result = False

    return result

def add_debug_info(message):
    debug_area.insert(tk.END, message + &quot;\n&quot;)
    debug_area.yview(tk.END)  # 자동 스크롤

root = tk.Tk()
root.title(&quot;transcoder connect&quot;)

frame = tk.Frame(root)
frame.pack(fill='both', expand=True)

row = 0
checkboxes = []
for addr in addresses:
    var = tk.BooleanVar()
    addr.checked = var
    checkbutton = tk.Checkbutton(frame, text=addr.host, variable=var)
    checkboxes.append(checkbutton)
    row += 1

# 체크박스 배치 및 프레임 넓이에 따라 자동 줄 바꿈 배치
def place_checkboxes():
    row, column = 0, 0
    frame.update_idletasks()  # 현재 프레임의 크기 업데이트
    frame_width = frame.winfo_width()  # 프레임의 너비
    padding = 5  # 적당한 패딩 값
    current_width = padding

    for checkbox in checkboxes:
        checkbox.grid_forget()  # 이전 그리드 설정을 초기화
        checkbox_width = checkbox.winfo_reqwidth()  # 체크박스의 요청 너비
        if current_width + checkbox_width &amp;gt; frame_width:
            row += 1
            column = 0
            current_width = padding
        checkbox.grid(row=row, column=column, sticky=&quot;w&quot;, padx=padding, pady=padding)
        current_width += checkbox_width + padding
        column += 1
        
# 초기 체크박스 배치
place_checkboxes()

# 창 크기 변경 시 체크박스 재배치
root.bind('&amp;lt;Configure&amp;gt;', lambda e: place_checkboxes())

button = tk.Button(root, text=&quot;connect&quot;, command=on_connect_button_click)
button.pack()

button2 = tk.Button(root, text=&quot;disconnect&quot;, command=on_disconnect_button_click)
button2.pack()

button3 = tk.Button(root, text=&quot;reset&quot;, command=on_reset_button_click)
button3.pack()

debug_area = scrolledtext.ScrolledText(root, wrap=tk.WORD)
debug_area.pack()

# 시작 !
add_debug_info(&quot;Initializing system...&quot;)

root.mainloop()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 요구사항이 복잡하지 않아 간단하게 구현할 수 있는 파이썬을 사용하였고 갠적으로는 주로 쓰는 언어가 아니라 코드가 좀 엉성할 수 있다 .. ㅎㅎ;&lt;/p&gt;</description>
      <category>button</category>
      <category>checkbutton</category>
      <category>Get</category>
      <category>Grid</category>
      <category>Python</category>
      <category>requests</category>
      <category>scrolledtext</category>
      <category>TK</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/231</guid>
      <comments>https://codereader37.tistory.com/231#entry231comment</comments>
      <pubDate>Sun, 9 Jun 2024 12:28:39 +0900</pubDate>
    </item>
    <item>
      <title>Singleton pattern</title>
      <link>https://codereader37.tistory.com/230</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;싱글턴 패턴은 소프트웨어 디자인 패턴 중 하나로 프로그램 내에 인스턴스가 오직 하나만 존재하도록 보장하는 패턴이다. 이 패턴은 전역 변수를 사용하지 않고 객체의 단일 인스턴스에 대한 전역적인 접근을 제공한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- example&lt;/p&gt;
&lt;pre id=&quot;code_1707709779735&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#ifndef _SINGLE_TON_TMPL_
#define _SINGLE_TON_TMPL_

#include &amp;lt;cstddef&amp;gt;

template &amp;lt;typename T&amp;gt;
class Singleton_tmpl : public T
{
public:
    Singleton_tmpl() {}
    ~Singleton_tmpl() {}

    static Singleton_tmpl *GetInstance()
    {
        if (Singleton_tmpl::m_pInstance == nullptr)
        {
            Singleton_tmpl::m_pInstance = new Singleton_tmpl;
        }

        m_nRefs++;
        return m_pInstance;
    }

    void Release()
    {
        if (m_nRefs &amp;gt; 0)
        {
            m_nRefs--;

            if ((m_nRefs == 0) &amp;amp;&amp;amp; (m_pInstance))
            {
                delete m_pInstance;
                m_pInstance = nullptr;
            }
        }
    }

private:
    static int m_nRefs;
    static Singleton_tmpl *m_pInstance;
};

// init staic variables 
template &amp;lt;typename T&amp;gt; Singleton_tmpl&amp;lt;T&amp;gt; *Singleton_tmpl&amp;lt;T&amp;gt;::m_pInstance = NULL;
template &amp;lt;typename T&amp;gt; int                Singleton_tmpl&amp;lt;T&amp;gt;::m_nRefs = 0; 

#endif&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 클래스 T를 상속받는 클래스를 정의하였다. 클래스 내 정적멤버 변수 m_pInstance, m_nRefs를 선언하여 싱글톤 인스턴스를 관리하며 클래스 외부에서 정적 멤버 변수들을 초기화 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1707710931606&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Singleton_tmpl&amp;lt;CDerivedClass&amp;gt; *pDrCls;
pDrcls = Singleton_tmpl::GetInstance();

pDrcls-&amp;gt;Functions();

if(pDrCls) 
{
    pDrCls-&amp;gt;Release();
    pDrcls = nullptr;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T타입으로 CDerivedClass를 사용하는 객체 변수를 선언하여 Getinstance()로 인스턴스를 할당 받는다. 처음 할당 받으면 인스턴스 생성과 동시에 m_nRefs값이 1이 되며 생성된 인스턴스가 반환될 것이고 이미 생성되어 있다면 m_nRefs 값이 1 증가하며 미리 생선된 인스턴스가 반환될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용이 완료된 pDrCls는 Release()를 호출하여 인스턴스 카운팅(m_nRefs)을 하나 줄이거나 인스턴스를(m_pInstance)를 해제 시킨다.&lt;/p&gt;</description>
      <category>instance</category>
      <category>Singleton</category>
      <category>template</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/230</guid>
      <comments>https://codereader37.tistory.com/230#entry230comment</comments>
      <pubDate>Mon, 12 Feb 2024 13:14:45 +0900</pubDate>
    </item>
    <item>
      <title>epoll</title>
      <link>https://codereader37.tistory.com/229</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;epoll은 리눅스에서 고성능 네트워크 프로그래밍을 위해 사용되는 I/O 이벤트 알림 모델이다. 대규모 파일 디스크럽터를 효율적으로 관리하며 이는 서버가 많은 수의 클라이언트와 동시에 통신해야 하는 고성능 네트워크 애플리케이션에 매우 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- epoll_create&lt;/p&gt;
&lt;pre id=&quot;code_1707529859714&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int epoll_create(int size);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;size만큼의 입출력 이벤트를 저장할 공간을 만든다. 그러나 리눅스 2.6.8 부터는 커널이 필요한 데이터의 크기를 동적으로 조정하기 때문에 0보다 큰 값만 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- epoll_ctl&lt;/p&gt;
&lt;pre id=&quot;code_1707530079765&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int epoll_ctl(int epfd, int op, int fd, struct epoll_events *event);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;epoll에 fd를 등록/수정/삭제 하는 함수로 epoll에서 관심있는 fd와 이 fd에서 발생할 event를 등록할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;op에 fd의 등록/변경/삭제를 결정하는 옵션들을 지정할 수 있다. ( EPOLL_CTL_ADD / EPOLL_CTL_MOD / EPPOL_CTL_DEL )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- epoll_wait&lt;/p&gt;
&lt;pre id=&quot;code_1707531292591&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int epoll_wait(int epfd, struct epoll_evnet *events, int maxevents, int timeout);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관심있는 fd들에게 무슨 일이 있었는지 검사한다. 검출할 사건들의 리스트를 events-&amp;gt;events[]로 전달하고 이벤트가 발생하면 발생한 이벤트 수를 리턴받는다. maxevents로 한번에 전달 받을 이벤트의 최대값을 지정할 수 있고 timeout으로 이벤트를 기다리는 시간을 밀리세컨드 단위로 전달할 수 있는데 -1을 전달하면 계속해서 이벤트를 기다리는 blocking 상태고 되고 0을 전달하면 이벤트 유무만 검사하고 즉시 리턴하는 상태가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- example&lt;/p&gt;
&lt;pre id=&quot;code_1707534153305&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;

using namespace std;

#include &amp;lt;sys/unistd.h&amp;gt;
#include &amp;lt;sys/socket.h&amp;gt;
#include &amp;lt;sys/epoll.h&amp;gt;
#include &amp;lt;arpa/inet.h&amp;gt;

#define SERVER_PORT 7001
#define BACKLOG 10
#define MAX_EVENTS 1000;

void setnonblocking(int sock)
{
    int flag = fcntl(sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flag | O_NONBLOCK);
}

int setup_socket()
{
    int sock;
    struct sockaddr_in sin;

    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) &amp;lt; 0)
    {
        return -1;
    }

    memset(&amp;amp;sin, 0, sizeof sin);

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    sin.sin_port = htons(SERVER_PORT);

    if (bind(sock, (struct sockaddr *)&amp;amp;sin, sizeof sin) &amp;lt; 0)
    {
        close(sock);
        return -1;
    }

    if (listen(sock, BACKLOG) &amp;lt; 0)
    {
        close(sock);
        return -1;
    }

    return sock;
}

int main()
{
    int server_fd = 0;
    int epoll_fd = 0;
    struct epoll_event event;
    struct epoll_event events[MAX_EVENTS];
    int event_count = 0;
    char buffer[1024] = {
        0,
    };

    // setup socket
    server_fd = setup_socket();
    if (server_fd &amp;lt; 0)
    {
        return 0;
    }

    // create epoll fd
    epoll_fd = epoll_create(100);
    if (epoll_fd &amp;lt; 0)
    {
        close(server_fd);
        return 0;
    }

    // set event
    memset(&amp;amp;event, 0, sizeof event);
    event.events = EPOLLIN | EPOLLHUP;
    event.data.fd = server_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &amp;amp;event) &amp;lt; 0)
    {
        close(server_fd);
        close(epoll_fd);
        return 0;
    }

    while (true)
    {
        event_count = epoll_wait(epoll_fd, epoll_events, MAX_EVENTS, 100);
        for (int i = 0; i &amp;lt; event_count; i++)
        {
            // accept
            if (epoll_events[i].data.fd == server_fd)
            {
                struct sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof client_addr;

                int client_fd = accept(server_fd, (struct sockaddr_in *)&amp;amp;client_addr, (socklen_t *)&amp;amp;client_addr_len);
                if (client_fd &amp;lt; 0)
                {
                    continue;
                }

                // set client_fd non-block
                setnonblocking(client_fd);

                // set event
                memset(&amp;amp;event, 0, sizeof event);
                event.events = EPOLLIN | EPOLLHUP;
                event.data.fd = client_fd;
                if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &amp;amp;event) &amp;lt; 0)
                {
                    close(client_fd);
                    continue;
                }
            }
            else
            {
                int client_fd = events[i].data.fd;
                int n = read(client_fd, buffer, buffer_fd);
                if (n &amp;lt; 0)
                { // error
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, &amp;amp;event);
                    close(client_fd);
                }
                else if (n == 0)
                { // client close
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, &amp;amp;event);
                    close(client_fd);
                }
                else
                { // read data
                    write(client_fd, buffer, n); // write echo message
                }
            }
        }
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server socket을 셋팅하고 epoll에 등록하여 client 접속 및 메시지를 처리하는 예제이다. 메시지를 받으면 받은 메시지를 바로 write하여 간단한 echo 역할을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 ) &lt;a href=&quot;https://jacking75.github.io/choiheungbae/문서/epoll을%20사용한%20비동기%20프로그래밍.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jacking75.github.io/choiheungbae/문서/epoll을%20사용한%20비동기%20프로그래밍.pdf&lt;/a&gt;&lt;/p&gt;</description>
      <category>epoll</category>
      <category>epoll_create</category>
      <category>epoll_ctl</category>
      <category>epoll_event</category>
      <category>epoll_wait</category>
      <category>Linux</category>
      <category>socket</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/229</guid>
      <comments>https://codereader37.tistory.com/229#entry229comment</comments>
      <pubDate>Fri, 9 Feb 2024 11:23:41 +0900</pubDate>
    </item>
    <item>
      <title>[c++] Nats Client</title>
      <link>https://codereader37.tistory.com/228</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Nats는 오픈소스 메시징 시스템을 지원하는 서비스의 한 종류로 다양한 응용프로그램 간의 효율적인 통신을 지원한다. 기본적으로 publisher와 subscriber로 구성되어 있으며 다양한 프로그래밍 언어에 대한 클라이언트 라이브러리를 제공하므로 다양한 언어로 작성된 애플리케이션 간의 통신을 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;c++로 작성된 client 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1707014875163&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;nats/nats.h&amp;gt;

void messageHandler(natsConnection* conn, natsSubscription* sub, natsMsg* msg, void* closure)
{
    // get data
    const char* data = natsMsg_GetData(msg);
    int dataLen = natsMsg_GetDataLength(msg);

    // print data
    std::cout &amp;lt;&amp;lt; &quot;Received message: &quot; &amp;lt;&amp;lt; std::string(data, dataLen) &amp;lt;&amp;lt; std::endl;

    // free msg
    natsMsg_Destroy(msg);
}

int main() 
{
    natsConnection* conn = NULL;
    natsOptions* opts = NULL;
    natsSubscription* subscription = NULL;
    natsMsg* msg = NULL;
    natsStatus status;

    // create opt
    status = natsOptions_Create(&amp;amp;opts);
    if (status != NATS_OK) {
        std::cerr &amp;lt;&amp;lt; &quot;Error creating NATS options : &quot; &amp;lt;&amp;lt; natsStatus_GetText(status) &amp;lt;&amp;lt; std::endl;
        return 1;
    }

    // set servers to opt
    const char* servers[] = {&quot;nats://server1:4222&quot;, &quot;nats://servers:4222&quot;};
    status = natsOptions_SetServers(opts, servers, 2);
    if (status != NATS_OK) {
        std::cerr &amp;lt;&amp;lt; &quot;Error setting NATS Server URLs : &quot; &amp;lt;&amp;lt; natsStatus_GetText(status) &amp;lt;&amp;lt; std::endl;
        natsOptions_Destroy(opts);
        return 1;
    }

    // connect nats server
    status = natsConnection_Connect(&amp;amp;conn, opts);
    if (status != NATS_OK) {
        std::cerr &amp;lt;&amp;lt; &quot;Error connecting to NATS Server : &quot; &amp;lt;&amp;lt; natsStatus_GetText(status) &amp;lt;&amp;lt; std::endl;
        natsOptions_Destory(opts);
        return 1;
    }

    // subscribe for get message
    const char* subject = &quot;example_subject&quot;;
    status = natsConnection_Subscribe(&amp;amp;subscription, conn, subject, messageHandler, NULL);
    if (status != NATS_OK) {
        std::cerr &amp;lt;&amp;lt; &quot;Error subscribing to subject : &quot; &amp;lt;&amp;lt; natsStatus_GetText(status) &amp;lt;&amp;lt; std::endl;
        natsConnection_Destroy(conn);
        natsOptions_Destroy(opts);
        return 1;
    }

    // create message object
    const char* subject = &quot;example_subject&quot;;
    const char* message = &quot;Hello,&quot;;
    status = natsMsg_Create(&amp;amp;msg, subject, NULL, (const void*)mmessage, stelen(message));
    if (status != NATS_OK) {
        std::cerr &amp;lt;&amp;lt; &quot;Error Creating NATS message : &quot; &amp;lt;&amp;lt; natsStatus_GetText(status) &amp;lt;&amp;lt; std::endl;
    } else {
        // publish message
        status = natsConnection_PublishMsg(conn, msg);
        if (status != NATS_OK) {
            std::cerr &amp;lt;&amp;lt; &quot;Error publishing message : &quot;
        }

        natsMsg_Destroy(msg);
    }

    // free
    natsSubscription_Destory(subscription);
    natsConnection_Destroy(conn);
    natsOptions_Destroy(opts);

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;publisher가 특정 subject 메시지를 송신하면 해당 subject를 구독하는 subscriber들이 이를 수신하게 된다.&lt;/p&gt;</description>
      <category>c++</category>
      <category>client</category>
      <category>connect</category>
      <category>MSG</category>
      <category>Nats</category>
      <category>option</category>
      <category>Publish</category>
      <category>subcribe</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/228</guid>
      <comments>https://codereader37.tistory.com/228#entry228comment</comments>
      <pubDate>Sun, 4 Feb 2024 12:12:36 +0900</pubDate>
    </item>
    <item>
      <title>[c++] dynamic_pointer_cast, static_pointer_cast</title>
      <link>https://codereader37.tistory.com/227</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;dynamic_pointer_cast, static_pointer_cast 는 c++에서 스마트 포인터를 다룰때 상/하향 캐스팅을 위해 사용된다. 여기서 상/하향 캐스팅은 자식 클래스에서 부모 클래스로 변환 ( 상향 캐스팅 ), 부모 클래스에서 자식 클래스로 변환 ( 하향 캐스팅 )을 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- dynamic_pointer_cast&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;dynamic_pointer_cast는 런타임에 타입의 안정성을 검사하는 동적 캐스팅을 수행한다. 이는 주로 하향 캐스팅 ( 부모 -&amp;gt; 자식 )에 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- static_pointer_cast&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;static_pointer_cast는 컴파일 타임에 수행하는 정적 캐스팅을 수행한다. 이는 상향 캐스팅( 자식 -&amp;gt; 부모 ), 하향 캐스팅 ( 부모 -&amp;gt; 자식 )에서 모두 쓰일 수 있지만 주로 상향 캐스팅에서 사용된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706948309810&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Base
{
public:
    int a;
    virtual void f() const { std::cout &amp;lt;&amp;lt; &quot;I am base!\n&quot;; }
    virtual ~Base() {}
};
 
class Derived : public Base
{
public:
    void f() const override { std::cout &amp;lt;&amp;lt; &quot;I am derived!\n&quot;; }
    ~Derived() {}
};

int main()
{
    auto base_ptr = std::make_shared&amp;lt;Base&amp;gt;();
    auto derived_ptr = std::make_shared&amp;lt;Derived&amp;gt;();
    
    auto upcast_ptr = std::static_pointer_cast&amp;lt;Base&amp;gt;(derived_ptr); // 상향 캐스팅
    auto downcast_ptr = std::dynamic_pointer_cast&amp;lt;Derived&amp;gt;(base_ptr); // 하향 캐스팅
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static_pointer_cast를 사용해 상향 캐스팅 ( Drieved -&amp;gt; Base )를 수행하고 dynamic_pointer_cast를 사용해 하향 캐스팅 ( Base -&amp;gt; Derived )을 하였다.&lt;/p&gt;</description>
      <category>dynamic_pointer_cast</category>
      <category>shared_ptr</category>
      <category>static_pointer_cast</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/227</guid>
      <comments>https://codereader37.tistory.com/227#entry227comment</comments>
      <pubDate>Sat, 3 Feb 2024 12:15:21 +0900</pubDate>
    </item>
    <item>
      <title>[c++] std::mutex를 사용하여 공유데이터 동기화 하기</title>
      <link>https://codereader37.tistory.com/226</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;여러 쓰레드에서 공유되는 데이터에 대해 동시에 접근하는 것을 방지하기 위해 std::mutex를 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1706946402788&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;vector&amp;gt;
#include &amp;lt;mutex&amp;gt;

int g_shared_data = 0;

std::mutex g_mtx;

void IncrementSharedData()
{
    // 스코프 기반 락 관리
    std::lock_guard&amp;lt;std::mutex&amp;gt; lock(g_mtx);
    
    g_shared_data++;
}

int main()
{
    std::vector&amp;lt;std::thread&amp;gt; threads;
    
    // 10개의 쓰레드 생성 및 실행
    for(int i=0; i &amp;lt; 0; i++)
    {
        threads.emplace_back(IncrementSharedData);
    }
    
    // 모든 쓰레드가 종료될때까지 기다림
    for(auto&amp;amp; thr : threads)
    {
        thr.join();
    }
    
    std::cout &amp;lt;&amp;lt; &quot;Final value of sharedData is &quot; &amp;lt;&amp;lt; sharedData &amp;lt;&amp;lt; std::endl;
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;std::lock_guard&amp;lt;std::mutex&amp;gt;를 사용하여 스코프 기반으로 동기화 관리를 할 수 있다. 특정 영역을 동기화 처리하려면 g_mtx.lock(), g_mtx.unlock() 함수로 감싸주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;emplace_back() 함수로 쓰레드 생성과 동시에 실행할 수 있다. 이 때 인자로 쓰레드 함수 (IncrementSharedData)를 넘겨주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thr.join() 함수로 쓰레드가 종료될 때까지 대기한다.&lt;/p&gt;</description>
      <category>emplace_back</category>
      <category>join</category>
      <category>Lock</category>
      <category>lock_guard</category>
      <category>mutex</category>
      <category>thread</category>
      <category>unlock</category>
      <category>동기화</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/226</guid>
      <comments>https://codereader37.tistory.com/226#entry226comment</comments>
      <pubDate>Sat, 3 Feb 2024 12:14:46 +0900</pubDate>
    </item>
    <item>
      <title>[c++] std::function, std::bind 사용하여 Callback 로직 구현하기</title>
      <link>https://codereader37.tistory.com/225</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;c++ 11 이상부터는 std::function, std::bind 사용하여 callback 함수를 묶어 호출하는 패턴을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706945017204&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CallbackClass {
public:
    void Callbackfunction(int x) {
        std::cout&amp;lt;&amp;lt; &quot;Callback Func Called :  &quot; &amp;lt;&amp;lt; x &amp;lt;&amp;lt; std::endl;
    }
}

void CallbackFunction2(int x, int y) {
    std::cout &amp;lt;&amp;lt; &quot;Callback Func Called : &quot; &amp;lt;&amp;lt; x &amp;lt;&amp;lt; std::endl;
}

int main() {
	CallbackClass cls;

    std::function&amp;lt;void(int)&amp;gt; cbMember = std::bind(&amp;amp;CallbackClass::Callbackfunction, &amp;amp;cls, std::placeholders::_1);
    std::function&amp;lt;void(int)&amp;gt; cbFunc = std::bind(&amp;amp;CallbackFunction2, std::placeholders::_1, std::placeholders::_2);
   	
    cbMemeber(1);
    cbFunc(2, 3);
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;member 함수를 bind 할 때는 클래스 object(&amp;amp;cls)를 매개변수로 전달해야 하고 std::placeholders::_1은 콜백함수로 전달되는 매개변수를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>bind</category>
      <category>c++</category>
      <category>Callback</category>
      <category>function</category>
      <category>Placeholder</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/225</guid>
      <comments>https://codereader37.tistory.com/225#entry225comment</comments>
      <pubDate>Sat, 3 Feb 2024 12:14:19 +0900</pubDate>
    </item>
    <item>
      <title>[c++] 범위 기반 for문 (Range-based for Loop)</title>
      <link>https://codereader37.tistory.com/224</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;범위 기반 for 문은 c++11 부터 도입된 문법으로 컨테이너의 모든 요소를 순회하기 위한 보다 간결하고 읽기 쉬운 방법을 제공한다. 이 구문은 Java의 enhanced for loop과 Python의 for-in loop과 비슷하다. Range-based for Loop은 컨테이너의 시작부터 끝까지 모든 요소를 순회하며 auto를 사용하여 각 요소에 대한 접근을 단순화 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706940051510&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::map&amp;lt;int, string&amp;gt; employee_map;

employee_map[0] = &quot;Kane&quot;;
employee_map[1] = &quot;Jane&quot;
employee_map[2] = &quot;Karr&quot;;

for (const auto&amp;amp; pair : employee_map)
{
    auto&amp;amp; no = pair.first;		// key 접근
    auto&amp;amp; name = pair.second;	// value 접근
    
    std::cout &amp;lt;&amp;lt; no &amp;lt;&amp;lt; &quot;_&quot; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; std::endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 map 데이터를 순회하며 키(first)와 값(second)에 접근하며 출력하는 예제이다. 값을 참조(&amp;amp;)로 접근하여 name 값을 변경하면 원본 데이터도 변경된다. =&amp;nbsp;&lt;/p&gt;</description>
      <category>auto</category>
      <category>FOR</category>
      <category>map</category>
      <category>범위기반for문</category>
      <author>코드베어</author>
      <guid isPermaLink="true">https://codereader37.tistory.com/224</guid>
      <comments>https://codereader37.tistory.com/224#entry224comment</comments>
      <pubDate>Sat, 3 Feb 2024 12:10:58 +0900</pubDate>
    </item>
  </channel>
</rss>