SlideShare a Scribd company logo
옥찬호 / 넥슨 (NEXON KOREA), Visual C++ MVP
녹슨 C++ 코드에 모던 C++로 기름칠하기
시작하기 전에…
• 모던 C++이란 C++11/14를 말합니다.
• C++11/14을 통한 개선 뿐만 아니라
기존 C++을 통한 개선 방법도 함께 포함합니다.
• 모던 C++을 모르는 분들을 위해 최대한 쉽게 설명합니다.
• 예제 코드가 많은 부분을 차지합니다.
녹슨 C++ 코드란?
int _output(
FILE* stream,
char const* format,
va_list arguments
)
{
// ...
}
#ifdef _UNICODE
int _woutput (
#else /* _UNICODE */
int _output (
#endif /* _UNICODE */
FILE* stream,
_TCHAR const* format,
va_list arguments
)
{
// ...
}
#ifdef _UNICODE
#ifdef POSITIONAL_PARAMETERS
int _woutput_p (
#else /* POSITIONAL_PARAMETERS */
int _woutput (
#endif /* POSITIONAL_PARAMETERS */
#else /* _UNICODE */
#ifdef POSITIONAL_PARAMETERS
int _output_p (
#else /* POSITIONAL_PARAMETERS */
int _output (
#endif /* POSITIONAL_PARAMETERS */
#endif /* _UNICODE */
FILE* stream,
_TCHAR const* format,
va_list arguments
)
{ ... }
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr)) {
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr)) {
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr)) {
DWORD dwFlags;
hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr)) {
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
if (SUCCEEDED(hr)) {
hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
if (SUCCEEDED(hr)) {
hr = pfd->SetFileTypeIndex(INDEX_WORDDOC);
if (SUCCEEDED(hr)) {
hr = pfd->SetDefaultExtension(L"doc;docx");
if (SUCCEEDED(hr)) {
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
고치고 싶다… 하지만
• 이미 고치기엔 길어져버린 코드
• 어디서부터 손을 써야 할 지 모름
• 코드는 점점 산으로…
• 아 귀찮다… ㅁㄴㅇㄹ
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
어디에 기름칠을 해볼까?
• 전처리기
• 리소스 관리
• 함수
• 타입, 반복문
• 기타 등등…
전처리기
조건부 컴파일
• #if, #ifdef, #ifndef, #elif, #else, …
• 많이 쓸수록 복잡해진다.
• 많이 쓸수록 이해하기 어렵다.
• 많이 쓸수록 유지보수하기 어렵다.
#ifdef _UNICODE
int _woutput (
#else /* _UNICODE */
int _output (
#endif /* _UNICODE */
FILE* stream,
_TCHAR const* format,
va_list arguments
)
{
// ...
}
template <typename T>
static int common_output(
FILE* stream,
T const* format,
va_list arguments
)
{
// ...
}
int _output(FILE* stream, char const* format, va_list const arguments) {
return common_output(stream, format, arguments);
}
int _woutput(FILE* stream, wchar_t const* format, va_list const arguments) {
return common_output(stream, format, arguments);
}
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
케이스 바이 케이스
• 타입에 따른 조건부 컴파일은 함수 템플릿을 통해 개선한다.
• 하지만 #ifdef를 사용해야 되는 경우도 있다.
• 32비트 vs 64비트 코드
• DEBUG 모드 vs Non-DEBUG 모드
• 컴파일러, 플랫폼, 언어에 따라 다른 코드
• 반드시 사용해야 된다면, 코드를 단순화하는 것이 좋다.
• 중첩 #ifdef를 피하고, 함수의 일부를 조건부 컴파일에 넣지 않도록 한다.
매크로
• #define …
• 변수 대신 사용하는 매크로 : #define RED 1
• 함수 대신 사용하는 매크로 : #define SQUARE(x) ((x) * (x))
• 수많은 문제를 일으키는 장본인
• 컴파일러가 타입에 대한 정보를 갖기 전에 계산됨
• 필요 이상으로 많이 사용
변수 대신 사용하는 매크로
#define red 0
#define orange 1
#define yellow 2
#define green 3
#define blue 4
#define purple 5
#define hot_pink 6
void f()
{
unsigned orange = 0xff9900;
}
warning C4091: '' : ignored on left of 'unsigned int' when no variable is declared
error C2143: syntax error : missing ';' before 'constant'
error C2106: '=' : left operand must be l-value
#define red 0
#define orange 1
#define yellow 2
#define green 3
#define blue 4
#define purple 5
#define hot_pink 6
void f()
{
unsigned 2 = 0xff00ff;
}
warning C4091: '' : ignored on left of 'unsigned int' when no variable is declared
error C2143: syntax error : missing ';' before 'constant'
error C2106: '=' : left operand must be l-value
#define RED 0
#define ORANGE 1
#define YELLOW 2
#define GREEN 3
#define BLUE 4
#define PURPLE 5
#define HOT_PINK 6
void g(int color); // valid values are 0 through 6
void f()
{
g(HOT_PINK); // Ok
g(9000); // Not ok, but compiler can’t tell
}
enum color_type
{
red = 0,
orange = 1,
yellow = 2,
green = 3,
blue = 4,
purple = 5,
hot_pink = 6
};
enum color_type
{
red, orange, yellow, green, blue, purple, hot_pink
};
void g(color_type color);
void f()
{
g(hot_pink); // Ok
g(9000); // Not ok, compiler will report error
}
error C2664: 'void g(color_type)' : cannot convert argument 1 from 'int' to 'color_type'
enum color_type
{
red, orange, yellow, green, blue, purple, hot_pink
};
void f()
{
int x = red; // Ugh
int x = red + orange; // Double ugh
}
enum color_type
{
red, orange, yellow, green, blue, purple, hot_pink
};
enum traffic_light_state
{
red, yellow, green
};
error C2365: 'red' : redefinition; previous definition was 'enumerator‘
error C2365: 'yellow' : redefinition; previous definition was 'enumerator‘
error C2365: 'green' : redefinition; previous definition was 'enumerator'
열거체의 문제점
• 묵시적인 int 변환
• 열거체의 타입을 명시하지 못함
• 이상한 범위 적용
→ 열거체 클래스(enum class)의 등장!
enum class color_type
{
red, orange, yellow, green, blue, purple, hot_pink
};
void g(color_type color);
void f()
{
g(color_type::red);
}
enum class color_type
{
red, orange, yellow, green, blue, purple, hot_pink
};
void g(color_type color);
void f()
{
int x = color_type::hot_pink;
}
error C2440: 'initializing' : cannot convert from 'color_type' to 'int'
enum class color_type
{
red, orange, yellow, green, blue, purple, hot_pink
};
void g(color_type color);
void f()
{
int x = static_cast<int>(color_type::hot_pink);
}
열거체 클래스를 사용하자
• 묵시적인 int 변환
→ 명시적인 int 변환
• 열거체의 타입을 명시하지 못함
→ 타입 명시 가능
• 이상한 범위 적용
→ 범위 지정 연산자를 통해 구분
함수 대신 사용하는 매크로
#define make_char_lowercase(c) 
((c) = (((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
void make_string_lowercase(char* s)
{
while (make_char_lowercase(*s++))
;
}
#define make_char_lowercase(c) 
((c) = (((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
void make_string_lowercase(char* s)
{
while (((*s++) = (((*s++) >= 'A') && ((*s++) <= 'Z'))
? ((*s++) - 'A' + 'a') : (*s++)))
;
}
// Old, ugly macro implementation:
#define make_char_lowercase(c) 
((c) = (((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
// New, better function implementation:
inline char make_char_lowercase(char& c)
{
if (c > 'A' && c < 'Z')
{
c = c - 'A' + 'a';
}
return c;
}
열거체, 함수를 사용하자
• 변수 대신 사용하는 매크로에는 열거체를 사용하자.
• 열거체에서 발생할 수 있는 문제는 enum class로 해결할 수 있다.
• 열거체 대신 ‘static const’ 변수를 사용하는 방법도 있다.
• 함수 대신 사용하는 매크로에는 함수를 사용하자.
• 읽기 쉽고, 유지보수하기 쉽고, 디버깅하기 쉽다.
• 성능에 따른 오버헤드도 없다.
리소스 관리
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr)) {
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr)) {
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr)) {
DWORD dwFlags;
hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr)) {
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
if (SUCCEEDED(hr)) {
hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
if (SUCCEEDED(hr)) {
hr = pfd->SetFileTypeIndex(INDEX_WORDDOC);
if (SUCCEEDED(hr)) {
hr = pfd->SetDefaultExtension(L"doc;docx");
if (SUCCEEDED(hr)) {
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, IID_PPV_ARGS(&pfd));
if (FAILED(hr))
return hr;
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (FAILED(hr))
return hr;
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (FAILED(hr))
return hr;
DWORD dwFlags;
hr = pfd->GetOptions(&dwFlags);
if (FAILED(hr))
return hr;
}
psiResult->Release();
}
}
}
}
}
}
}
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
pfd->Release();
}
return hr;
void ExampleWithoutRAII() {
std::FILE* file_handle = std::fopen("logfile.txt", "w+");
if (file_handle == nullptr)
throw std::runtime_error("File couldn't open!");
try {
if (std::fputs("Hello, Log File!", file_handle) == EOF)
throw std::runtime_error("File couldn't write!");
// continue writing to logfile.txt ... do not return
// prematurely, as cleanup happens at the end of this function
}
catch (...)
{
std::fclose(file_handle);
throw;
}
std::fclose(file_handle);
}
RAII
• 자원 획득은 초기화다 (Resource Acquisition Is Initialization)
• 객체의 생성에 맞춰 메모리와 시스템 리소스를 자동으로 할당
• 객체의 소멸에 맞춰 메모리와 시스템 리소스를 자동으로 해제
→ 생성자 안에서 리소스를 할당하고, 소멸자에서 리소스를 해제
void ExampleWithRAII()
{
// open file (acquire resource)
File logFile("logfile.txt");
logFile.Write("Hello, Log File!");
// continue writing to logfile.txt ...
}
File::File(const char* filename)
: m_file_handle(std::fopen(filename, "w+"))
{
if (m_file_handle == NULL)
throw openError();
}
File::~File()
{
std::fclose(m_file_handle);
}
void ExampleWithRAII()
{
// open file (acquire resource)
File* logFile = new File("logfile.txt");
logFile->Write("Hello, Log File!");
// continue writing to logfile.txt ...
}
File::File(const char* filename)
: m_file_handle(std::fopen(filename, "w+"))
{
if (m_file_handle == NULL)
throw openError();
}
File::~File()
{
std::fclose(m_file_handle);
}
다시 발생하는 문제
• 파일 입출력과 관련한 예외 처리를 간편하게 하기 위해
File 클래스를 만들어 생성자와 소멸자로 처리했다.
• 하지만, 정작 File 클래스를 동적으로 할당하는 경우
소멸자가 호출되지 않아 파일을 닫지 않는 문제가 발생한다.
• 좋은 방법이 없을까?
→ 스마트 포인터(Smart Pointer)의 등장!
스마트 포인터
• 좀 더 똑똑한 포인터
• 스마트 포인터를 사용하면 명시적으로 해제할 필요가 없다.
• 사용하는 이유
• 적은 버그, 자동 청소, 자동 초기화
• Dangling 포인터 발생 X, Exception 안전
• 효율성
void ExampleWithRAII()
{
// open file (acquire resource)
std::unique_ptr<File> logFile = std::make_unique<File>("logfile.txt");
logFile->Write("Hello, Log File!");
// continue writing to logfile.txt ...
}
File::File(const char* filename)
: m_file_handle(std::fopen(filename, "w+"))
{
if (m_file_handle == NULL)
throw openError();
}
File::~File()
{
std::fclose(m_file_handle);
}
스마트 포인터의 종류
• 경우에 따라 여러 종류의 스마트 포인터를 사용할 수 있다.
• shared_ptr : 객체의 소유권을 복사할 수 있는 포인터
(여러 shared_ptr 객체가 같은 포인터 객체를 가리킬 수 있음)
• unique_ptr : 객체의 소유권을 복사할 수 없는 포인터
(하나의 unique_ptr 객체만이 하나의 포인터 객체를 가리킬 수 있음)
std::unique_ptr
ptrA Song 개체
ptrA Song 개체
ptrB
auto ptrA = std::make_unique<Song>(L"Diana Krall", L"The Look of Love");
auto ptrB = std::move(ptrA);
std::unique_ptr<Song> SongFactory(const std::wstring& artist, const std::wstring& title)
{
// Implicit move operation into the variable that stores the result.
return std::make_unique<Song>(artist, title);
}
void MakeSongs()
{
// Create a new unique_ptr with a new object.
auto song = std::make_unique<Song>(L"Mr. Children", L"Namonaki Uta");
// Use the unique_ptr.
std::vector<std::wstring> titles = { song->title };
// Move raw pointer from one unique_ptr to another.
std::unique_ptr<Song> song2 = std::move(song);
// Obtain unique_ptr from function that returns by value.
auto song3 = SongFactory(L"Michael Jackson", L"Beat It");
}
std::shared_ptr
MyClass
제어 블록 참조 개수 = 1
개체에 대한 포인터
제어 블록에 대한 포인터
p1
std::shared_ptr
MyClass
제어 블록 참조 개수 = 2
개체에 대한 포인터
제어 블록에 대한 포인터
p1
개체에 대한 포인터
제어 블록에 대한 포인터
p2
// Use make_shared function when possible.
auto sp1 = std::make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You");
// Ok, but slightly less efficient.
// Note: Using new expression as constructor argument
// creates no named variable for other code to access.
std::shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance"));
// When initialization must be separate from declaration, e.g. class members,
// initialize with nullptr to make your programming intent explicit.
std::shared_ptr<Song> sp5(nullptr);
//Equivalent to: shared_ptr<Song> sp5;
//...
sp5 = std::make_shared<Song>(L"Elton John", L"I'm Still Standing");
리소스 관리는 스마트 포인터로
• RAII를 사용하자!
• 읽고, 쓰고, 유지보수하기 쉽다.
• 자원 관리에 대한 걱정을 할 필요가 없다.
• C++ 코드 품질을 향상시키는 가장 쉬운 방법!
• 기왕이면 스마트 포인터로!
• shared_ptr
• unique_ptr
함수
std::vector<int>::const_iterator iter = cardinal.begin();
std::vector<int>::const_iterator iter_end = cardinal.end();
int total_elements = 1;
while (iter != iter_end)
{
total_elements *= *iter;
++iter;
}
template <typename T>
struct product {
product(T& storage) : value(storage) {}
template<typename V>
void operator()(V& v)
{
value *= v;
}
T& value;
};
std::vector<int> cardinal;
int total_elements = 1;
for_each(cardinal.begin(), cardinal.end(),
product<int>(total_elements));
int total_elements = 1;
for_each(cardinal.begin(), cardinal.end(), [&total_elements](int i)
{
total_elements *= i;
});
struct mod
{
mod(int m) : modulus(m) {}
int operator()(int v)
{ return v % modulus; }
int modulus;
};
int my_mod = 8;
std::transform(in.begin(), in.end(),
out.begin(), mod(my_mod));
int my_mod = 8;
transform(in.begin(), in.end(), out.begin(),
[my_mod](int v) -> int
{ return v % my_mod; });
Functor Lambda Expression
람다식
[my_mod] (int v) -> int { return v % my_mod; }
개시자
(Introducer Capture)
인자
(Arguments)
반환 타입
(Return Type)
함수의 몸통
(Statement)
int x = 10, y = 20;
[] {}; // capture 하지 않음
[x] (int arg) { return x; }; // value(Copy) capture x
[=] { return x; }; // value(Copy) capture all
[&] { return y; }; // reference capture all
[&, x] { return y; }; // reference capture all except x
[=, &y] { return x; }; // value(Copy) capture all except y
[this] { return this->something; }; // this capture
[=, x] {}; // error
[&, &x] {}; // error
[=, this] {}; // error
[x, x] {}; // error
1
2
2
void fa(int x, function<void(void)> f) { ++x; f(); }
void fb(int x, function<void(int)> f) { ++x; f(x); }
void fc(int &x, function<void(void)> f) { ++x; f(); }
int x = 1;
fa(x, [x] { cout << x << endl; });
fb(x, [](int x) { cout << x << endl; });
fc(x, [&x] { cout << x << endl; });
WNDCLASSEX wcex;
wcex.lpfnWndProc= [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ->
LRESULT {
switch (message) {
case WM_COMMAND:
EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
char szText[256];
GetWindowTextA(hwnd, szText, 256);
cout << szText << endl;
return TRUE;
}, 0);
HANDLE hT = CreateThread(NULL, 0, [](LPVOID lpThreadParameter) -> DWORD {
for (int i = 0; i < 1000; i++) {
this_thread::sleep_for(milliseconds{ 10 });
cout << i << endl;
}
return 0;
}, NULL, 0, NULL);
람다식을 사용하자
• 짧고, 간결하고, while 문과 같은 행사 코드 없이
깔끔하게 작성할 수 있다.
• 수십줄의 코드를 1~2줄로 간추릴 수 있다.
• Functor, Callback Function을 대체해서 사용할 수 있다.
• 반복적으로 사용하는 함수가 아니라면 람다식을 사용하자!
간단하게 적용 가능한 기능들
auto 키워드
• 컴파일 타임에 타입을 추론해 어떤 타입인지 결정한다.
• 컴파일 타임에 추론이 불가능하다면, 오류가 발생한다.
std::vector<std::tuple<std::string, int, double>> vStudents;
for (std::vector<std::tuple<std::string, int, double>>::iterator iter =
vStudents.begin(); iter != vStudents.end(); ++iter) { … }
std::vector<std::tuple<std::string, int, double>> vStudents;
for (auto iter = vStudents.begin(); iter != vStudents.end(); ++iter) { … }
범위 기반 for문
int arr[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 5; ++i)
std::cout << arr[i] << std::endl;
return 0;
}
int arr[] = { 1, 2, 3, 4, 5 };
for (auto& i : arr)
std::cout << i << std::endl;
return 0;
}
정리
// circle and shape are user-defined types
circle* p = new circle(42);
vector<shape*> v = load_shapes();
for (vector<circle*>::iterator i = v.begin(); i != v.end(); ++i) {
if (*i && **i == *p)
cout << **i << " is a matchn";
}
for (vector<circle*>::iterator i = v.begin(); i != v.end(); ++i) {
delete *i; // not exception safe
}
delete p;
정리
// circle and shape are user-defined types
auto p = make_shared<circle>(42);
vector<shared_ptr<shape>> v = load_shapes();
for_each(begin(v), end(v), [&](const shared_ptr<shape>& s) {
if (s && *s == *p)
cout << *s << " is a matchn";
});
정리
• 대체할 수 있는 조건부 컴파일은 템플릿으로 기름칠!
• 매크로는 가급적 사용하지 말고 열거체와 함수로 기름칠!
• 리소스 관리에는 RAII, 기왕이면 스마트 포인터로 기름칠!
• 일회성으로 사용하는 함수는 람다식으로 기름칠!
• 복잡한 타입에는 auto로 기름칠!
• 반복 횟수에 고통받지 말고 범위 기반 for문으로 기름칠!
정리
• 모던 C++을 통해 대체할 수 있는 코드는 많습니다!
(하지만 제한된 시간으로 인해 …)
• 다음 사이트에서 모던 C++ 예제 코드를 확인하실 수 있습니다.
http://www.github.com/utilForever/ModernCpp
• C++ 핵심 가이드라인
• 영문 : https://github.com/isocpp/CppCoreGuidelines
• 한글 : https://github.com/CppKorea/CppCoreGuidelines
Quiz
#include <iostream>
#include <memory>
#include <vector>
class C {
public:
void foo() { std::cout << "A"; }
void foo() const { std::cout << "B"; }
};
struct S {
std::vector<C> v;
std::unique_ptr<C> u;
C* const p;
S() : v(1), u(new C()), p(u.get()) {}
};
Quiz #1
int main() {
S s;
const S& r = s;
s.v[0].foo(); s.u->foo(); s.p->foo();
r.v[0].foo(); r.u->foo(); r.p->foo();
}
AAABAA
#include <iostream>
struct A {
A() { std::cout << "A"; }
A(const A& a) { std::cout << "B"; }
virtual void f() { std::cout << "C"; }
};
int main() {
A a[2];
for (auto x : a) {
x.f();
}
}
Quiz #2
AABCBC
#include <iostream>
struct A {
A() { std::cout << "A"; }
A(const A& a) { std::cout << "B"; }
virtual void f() { std::cout << "C"; }
};
int main() {
A a[2];
for (auto& x : a) {
x.f();
}
}
Quiz #3
AACC
C++ Korea
• http://www.facebook.com/groups/cppkorea
http://www.github.com/cppkorea
감사합니다.
• MSDN Forum http://aka.ms/msdnforum
• TechNet Forum http://aka.ms/technetforum
http://aka.ms/td2015_again
TechDays Korea 2015에서 놓치신 세션은
Microsoft 기술 동영상 커뮤니티 Channel 9에서
추후에 다시 보실 수 있습니다.

More Related Content

PPTX
Clean Code
PDF
[C++ Korea] Effective Modern C++ Study, Item 1 - 3
PDF
C++20 Key Features Summary
PDF
闇魔術を触ってみた
PDF
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기
PDF
직장인을 위한 GTD 시작하기 (How To Start GTD)
PDF
Event-sourced architectures with Akka
PDF
研究動向から考えるx86/x64最適化手法
Clean Code
[C++ Korea] Effective Modern C++ Study, Item 1 - 3
C++20 Key Features Summary
闇魔術を触ってみた
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기
직장인을 위한 GTD 시작하기 (How To Start GTD)
Event-sourced architectures with Akka
研究動向から考えるx86/x64最適化手法

What's hot (20)

PDF
C++17 Key Features Summary - Ver 2
PPTX
Exception Handling in object oriented programming using C++
PDF
An introduction to Rust: the modern programming language to develop safe and ...
PDF
C++の黒魔術
PDF
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
PDF
Clean code
PDF
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
PPTX
キャッシュコヒーレントに囚われない並列カウンタ達
PDF
CRDT in 15 minutes
PDF
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
PDF
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호
PDF
Design functional solutions in Java, a practical example
PDF
templateとautoの型推論
PPTX
Clean Code Principles
PDF
Advanced Python Testing Techniques (Pycon KR 2019) [Korean Ver.]
PDF
Lazy java
PPTX
PDF
éNoncés+corrections bac2009
PDF
Domain Driven Design with the F# type System -- NDC London 2013
PPTX
The Clean Architecture
C++17 Key Features Summary - Ver 2
Exception Handling in object oriented programming using C++
An introduction to Rust: the modern programming language to develop safe and ...
C++の黒魔術
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
Clean code
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
キャッシュコヒーレントに囚われない並列カウンタ達
CRDT in 15 minutes
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호
Design functional solutions in Java, a practical example
templateとautoの型推論
Clean Code Principles
Advanced Python Testing Techniques (Pycon KR 2019) [Korean Ver.]
Lazy java
éNoncés+corrections bac2009
Domain Driven Design with the F# type System -- NDC London 2013
The Clean Architecture
Ad

Viewers also liked (20)

PDF
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기
PDF
[C++ Korea 2nd Seminar] C++17 Key Features Summary
PDF
C++ Programming - 14th Study
PDF
[C++ Korea] Effective Modern C++ Study, Item 27, 29 - 30
PDF
C++ Programming - 11th Study
PDF
Data Structure - 2nd Study
PDF
Data Structure - 1st Study
PDF
게임 프로그래밍 기초 공부법
PDF
[C++ Korea] Effective Modern C++ Study, Item 11 - 13
PDF
C++ Programming - 4th Study
PDF
Akamai Korea - Tech Day (2015/03/11) HTTP/2
PDF
2013 C++ Study For Students #1
PDF
C++ Programming - 13th Study
PDF
C++ Programming - 9th Study
PDF
C++ Programming - 10th Study
PDF
C++ Programming - 8th Study
PDF
C++ Programming - 7th Study
PDF
MSBuild + Git + Jenkins
PDF
C++ Programming - 12th Study
PPTX
[NHN_NEXT] DirectX Tutorial 강의 자료
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기
[C++ Korea 2nd Seminar] C++17 Key Features Summary
C++ Programming - 14th Study
[C++ Korea] Effective Modern C++ Study, Item 27, 29 - 30
C++ Programming - 11th Study
Data Structure - 2nd Study
Data Structure - 1st Study
게임 프로그래밍 기초 공부법
[C++ Korea] Effective Modern C++ Study, Item 11 - 13
C++ Programming - 4th Study
Akamai Korea - Tech Day (2015/03/11) HTTP/2
2013 C++ Study For Students #1
C++ Programming - 13th Study
C++ Programming - 9th Study
C++ Programming - 10th Study
C++ Programming - 8th Study
C++ Programming - 7th Study
MSBuild + Git + Jenkins
C++ Programming - 12th Study
[NHN_NEXT] DirectX Tutorial 강의 자료
Ad

Similar to [TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기 (20)

PPTX
이펙티브 C++ (7~9)
PDF
PPTX
Effective C++ Chaper 1
PDF
Effective C++ Chapter 1 Summary
PDF
7 8 1
PPTX
Effective c++(chapter 5,6)
PDF
학교에서 배우지 않는 C
PDF
HI-ARC PS 101
PDF
Api design for c++ 6장
PDF
C++ Advanced 강의 5주차
PPTX
Effective cpp
PPTX
Effective c++chapter1 and2
PDF
Effective c++ chapter1 2_dcshin
PDF
[데브루키] 게임 엔진 아키텍쳐_3장_게임을 위한 소프트웨어 엔지니어링 기초
PPTX
PS에 쓸 수 있도록 C++ 입문하기.pptx ㅔ뱆더게ㅠㅐㅓㅔㅂ대ㅓ규ㅔㅐㅓ
PPTX
More effective c++ 2
PDF
C++ api design 품질
PPTX
A tour of C++ : the basics
PPTX
Effective c++ chapter 7,8
PPTX
이펙티브 C++ 5,6 장 스터디
이펙티브 C++ (7~9)
Effective C++ Chaper 1
Effective C++ Chapter 1 Summary
7 8 1
Effective c++(chapter 5,6)
학교에서 배우지 않는 C
HI-ARC PS 101
Api design for c++ 6장
C++ Advanced 강의 5주차
Effective cpp
Effective c++chapter1 and2
Effective c++ chapter1 2_dcshin
[데브루키] 게임 엔진 아키텍쳐_3장_게임을 위한 소프트웨어 엔지니어링 기초
PS에 쓸 수 있도록 C++ 입문하기.pptx ㅔ뱆더게ㅠㅐㅓㅔㅂ대ㅓ규ㅔㅐㅓ
More effective c++ 2
C++ api design 품질
A tour of C++ : the basics
Effective c++ chapter 7,8
이펙티브 C++ 5,6 장 스터디

More from Chris Ohk (20)

PDF
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
PDF
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
PDF
Momenti Seminar - 5 Years of RosettaStone
PDF
Momenti Seminar - A Tour of Rust, Part 2
PDF
Momenti Seminar - A Tour of Rust, Part 1
PDF
Evolving Reinforcement Learning Algorithms, JD. Co-Reyes et al, 2021
PDF
Adversarially Guided Actor-Critic, Y. Flet-Berliac et al, 2021
PDF
Agent57: Outperforming the Atari Human Benchmark, Badia, A. P. et al, 2020
PDF
Proximal Policy Optimization Algorithms, Schulman et al, 2017
PDF
Trust Region Policy Optimization, Schulman et al, 2015
PDF
Continuous Control with Deep Reinforcement Learning, lillicrap et al, 2015
PDF
GDG Gwangju DevFest 2019 - <하스스톤> 강화학습 환경 개발기
PDF
[RLKorea] <하스스톤> 강화학습 환경 개발기
PDF
[NDC 2019] 하스스톤 강화학습 환경 개발기
PDF
[델리만주] 대학원 캐슬 - 석사에서 게임 프로그래머까지
PDF
디미고 특강 - 개발을 시작하려는 여러분에게
PDF
청강대 특강 - 프로젝트 제대로 해보기
PDF
[NDC 2018] 유체역학 엔진 개발기
PDF
My Way, Your Way
PDF
Re:Zero부터 시작하지 않는 오픈소스 개발
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
Momenti Seminar - 5 Years of RosettaStone
Momenti Seminar - A Tour of Rust, Part 2
Momenti Seminar - A Tour of Rust, Part 1
Evolving Reinforcement Learning Algorithms, JD. Co-Reyes et al, 2021
Adversarially Guided Actor-Critic, Y. Flet-Berliac et al, 2021
Agent57: Outperforming the Atari Human Benchmark, Badia, A. P. et al, 2020
Proximal Policy Optimization Algorithms, Schulman et al, 2017
Trust Region Policy Optimization, Schulman et al, 2015
Continuous Control with Deep Reinforcement Learning, lillicrap et al, 2015
GDG Gwangju DevFest 2019 - <하스스톤> 강화학습 환경 개발기
[RLKorea] <하스스톤> 강화학습 환경 개발기
[NDC 2019] 하스스톤 강화학습 환경 개발기
[델리만주] 대학원 캐슬 - 석사에서 게임 프로그래머까지
디미고 특강 - 개발을 시작하려는 여러분에게
청강대 특강 - 프로젝트 제대로 해보기
[NDC 2018] 유체역학 엔진 개발기
My Way, Your Way
Re:Zero부터 시작하지 않는 오픈소스 개발

[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기

  • 1. 옥찬호 / 넥슨 (NEXON KOREA), Visual C++ MVP 녹슨 C++ 코드에 모던 C++로 기름칠하기
  • 2. 시작하기 전에… • 모던 C++이란 C++11/14를 말합니다. • C++11/14을 통한 개선 뿐만 아니라 기존 C++을 통한 개선 방법도 함께 포함합니다. • 모던 C++을 모르는 분들을 위해 최대한 쉽게 설명합니다. • 예제 코드가 많은 부분을 차지합니다.
  • 4. int _output( FILE* stream, char const* format, va_list arguments ) { // ... }
  • 5. #ifdef _UNICODE int _woutput ( #else /* _UNICODE */ int _output ( #endif /* _UNICODE */ FILE* stream, _TCHAR const* format, va_list arguments ) { // ... }
  • 6. #ifdef _UNICODE #ifdef POSITIONAL_PARAMETERS int _woutput_p ( #else /* POSITIONAL_PARAMETERS */ int _woutput ( #endif /* POSITIONAL_PARAMETERS */ #else /* _UNICODE */ #ifdef POSITIONAL_PARAMETERS int _output_p ( #else /* POSITIONAL_PARAMETERS */ int _output ( #endif /* POSITIONAL_PARAMETERS */ #endif /* _UNICODE */ FILE* stream, _TCHAR const* format, va_list arguments ) { ... }
  • 7. IFileDialog *pfd = NULL; HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pfd)); if (SUCCEEDED(hr)) { IFileDialogEvents *pfde = NULL; hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde)); if (SUCCEEDED(hr)) { DWORD dwCookie; hr = pfd->Advise(pfde, &dwCookie); if (SUCCEEDED(hr)) { DWORD dwFlags; hr = pfd->GetOptions(&dwFlags); if (SUCCEEDED(hr)) { hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM); if (SUCCEEDED(hr)) { hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes); if (SUCCEEDED(hr)) { hr = pfd->SetFileTypeIndex(INDEX_WORDDOC); if (SUCCEEDED(hr)) { hr = pfd->SetDefaultExtension(L"doc;docx"); if (SUCCEEDED(hr)) {
  • 9. 고치고 싶다… 하지만 • 이미 고치기엔 길어져버린 코드 • 어디서부터 손을 써야 할 지 모름 • 코드는 점점 산으로… • 아 귀찮다… ㅁㄴㅇㄹ
  • 11. 어디에 기름칠을 해볼까? • 전처리기 • 리소스 관리 • 함수 • 타입, 반복문 • 기타 등등…
  • 13. 조건부 컴파일 • #if, #ifdef, #ifndef, #elif, #else, … • 많이 쓸수록 복잡해진다. • 많이 쓸수록 이해하기 어렵다. • 많이 쓸수록 유지보수하기 어렵다.
  • 14. #ifdef _UNICODE int _woutput ( #else /* _UNICODE */ int _output ( #endif /* _UNICODE */ FILE* stream, _TCHAR const* format, va_list arguments ) { // ... }
  • 15. template <typename T> static int common_output( FILE* stream, T const* format, va_list arguments ) { // ... } int _output(FILE* stream, char const* format, va_list const arguments) { return common_output(stream, format, arguments); } int _woutput(FILE* stream, wchar_t const* format, va_list const arguments) { return common_output(stream, format, arguments); }
  • 16. // Check windows #if _WIN32 || _WIN64 #if _WIN64 #define ENVIRONMENT64 #else #define ENVIRONMENT32 #endif #endif // Check GCC #if __GNUC__ #if __x86_64__ || __ppc64__ #define ENVIRONMENT64 #else #define ENVIRONMENT32 #endif #endif
  • 17. 케이스 바이 케이스 • 타입에 따른 조건부 컴파일은 함수 템플릿을 통해 개선한다. • 하지만 #ifdef를 사용해야 되는 경우도 있다. • 32비트 vs 64비트 코드 • DEBUG 모드 vs Non-DEBUG 모드 • 컴파일러, 플랫폼, 언어에 따라 다른 코드 • 반드시 사용해야 된다면, 코드를 단순화하는 것이 좋다. • 중첩 #ifdef를 피하고, 함수의 일부를 조건부 컴파일에 넣지 않도록 한다.
  • 18. 매크로 • #define … • 변수 대신 사용하는 매크로 : #define RED 1 • 함수 대신 사용하는 매크로 : #define SQUARE(x) ((x) * (x)) • 수많은 문제를 일으키는 장본인 • 컴파일러가 타입에 대한 정보를 갖기 전에 계산됨 • 필요 이상으로 많이 사용
  • 20. #define red 0 #define orange 1 #define yellow 2 #define green 3 #define blue 4 #define purple 5 #define hot_pink 6 void f() { unsigned orange = 0xff9900; } warning C4091: '' : ignored on left of 'unsigned int' when no variable is declared error C2143: syntax error : missing ';' before 'constant' error C2106: '=' : left operand must be l-value
  • 21. #define red 0 #define orange 1 #define yellow 2 #define green 3 #define blue 4 #define purple 5 #define hot_pink 6 void f() { unsigned 2 = 0xff00ff; } warning C4091: '' : ignored on left of 'unsigned int' when no variable is declared error C2143: syntax error : missing ';' before 'constant' error C2106: '=' : left operand must be l-value
  • 22. #define RED 0 #define ORANGE 1 #define YELLOW 2 #define GREEN 3 #define BLUE 4 #define PURPLE 5 #define HOT_PINK 6 void g(int color); // valid values are 0 through 6 void f() { g(HOT_PINK); // Ok g(9000); // Not ok, but compiler can’t tell }
  • 23. enum color_type { red = 0, orange = 1, yellow = 2, green = 3, blue = 4, purple = 5, hot_pink = 6 };
  • 24. enum color_type { red, orange, yellow, green, blue, purple, hot_pink }; void g(color_type color); void f() { g(hot_pink); // Ok g(9000); // Not ok, compiler will report error } error C2664: 'void g(color_type)' : cannot convert argument 1 from 'int' to 'color_type'
  • 25. enum color_type { red, orange, yellow, green, blue, purple, hot_pink }; void f() { int x = red; // Ugh int x = red + orange; // Double ugh }
  • 26. enum color_type { red, orange, yellow, green, blue, purple, hot_pink }; enum traffic_light_state { red, yellow, green }; error C2365: 'red' : redefinition; previous definition was 'enumerator‘ error C2365: 'yellow' : redefinition; previous definition was 'enumerator‘ error C2365: 'green' : redefinition; previous definition was 'enumerator'
  • 27. 열거체의 문제점 • 묵시적인 int 변환 • 열거체의 타입을 명시하지 못함 • 이상한 범위 적용 → 열거체 클래스(enum class)의 등장!
  • 28. enum class color_type { red, orange, yellow, green, blue, purple, hot_pink }; void g(color_type color); void f() { g(color_type::red); }
  • 29. enum class color_type { red, orange, yellow, green, blue, purple, hot_pink }; void g(color_type color); void f() { int x = color_type::hot_pink; } error C2440: 'initializing' : cannot convert from 'color_type' to 'int'
  • 30. enum class color_type { red, orange, yellow, green, blue, purple, hot_pink }; void g(color_type color); void f() { int x = static_cast<int>(color_type::hot_pink); }
  • 31. 열거체 클래스를 사용하자 • 묵시적인 int 변환 → 명시적인 int 변환 • 열거체의 타입을 명시하지 못함 → 타입 명시 가능 • 이상한 범위 적용 → 범위 지정 연산자를 통해 구분
  • 33. #define make_char_lowercase(c) ((c) = (((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) void make_string_lowercase(char* s) { while (make_char_lowercase(*s++)) ; }
  • 34. #define make_char_lowercase(c) ((c) = (((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) void make_string_lowercase(char* s) { while (((*s++) = (((*s++) >= 'A') && ((*s++) <= 'Z')) ? ((*s++) - 'A' + 'a') : (*s++))) ; }
  • 35. // Old, ugly macro implementation: #define make_char_lowercase(c) ((c) = (((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) // New, better function implementation: inline char make_char_lowercase(char& c) { if (c > 'A' && c < 'Z') { c = c - 'A' + 'a'; } return c; }
  • 36. 열거체, 함수를 사용하자 • 변수 대신 사용하는 매크로에는 열거체를 사용하자. • 열거체에서 발생할 수 있는 문제는 enum class로 해결할 수 있다. • 열거체 대신 ‘static const’ 변수를 사용하는 방법도 있다. • 함수 대신 사용하는 매크로에는 함수를 사용하자. • 읽기 쉽고, 유지보수하기 쉽고, 디버깅하기 쉽다. • 성능에 따른 오버헤드도 없다.
  • 38. IFileDialog *pfd = NULL; HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pfd)); if (SUCCEEDED(hr)) { IFileDialogEvents *pfde = NULL; hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde)); if (SUCCEEDED(hr)) { DWORD dwCookie; hr = pfd->Advise(pfde, &dwCookie); if (SUCCEEDED(hr)) { DWORD dwFlags; hr = pfd->GetOptions(&dwFlags); if (SUCCEEDED(hr)) { hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM); if (SUCCEEDED(hr)) { hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes); if (SUCCEEDED(hr)) { hr = pfd->SetFileTypeIndex(INDEX_WORDDOC); if (SUCCEEDED(hr)) { hr = pfd->SetDefaultExtension(L"doc;docx"); if (SUCCEEDED(hr)) {
  • 39. IFileDialog *pfd = NULL; HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, IID_PPV_ARGS(&pfd)); if (FAILED(hr)) return hr; IFileDialogEvents *pfde = NULL; hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde)); if (FAILED(hr)) return hr; DWORD dwCookie; hr = pfd->Advise(pfde, &dwCookie); if (FAILED(hr)) return hr; DWORD dwFlags; hr = pfd->GetOptions(&dwFlags); if (FAILED(hr)) return hr;
  • 41. void ExampleWithoutRAII() { std::FILE* file_handle = std::fopen("logfile.txt", "w+"); if (file_handle == nullptr) throw std::runtime_error("File couldn't open!"); try { if (std::fputs("Hello, Log File!", file_handle) == EOF) throw std::runtime_error("File couldn't write!"); // continue writing to logfile.txt ... do not return // prematurely, as cleanup happens at the end of this function } catch (...) { std::fclose(file_handle); throw; } std::fclose(file_handle); }
  • 42. RAII • 자원 획득은 초기화다 (Resource Acquisition Is Initialization) • 객체의 생성에 맞춰 메모리와 시스템 리소스를 자동으로 할당 • 객체의 소멸에 맞춰 메모리와 시스템 리소스를 자동으로 해제 → 생성자 안에서 리소스를 할당하고, 소멸자에서 리소스를 해제
  • 43. void ExampleWithRAII() { // open file (acquire resource) File logFile("logfile.txt"); logFile.Write("Hello, Log File!"); // continue writing to logfile.txt ... } File::File(const char* filename) : m_file_handle(std::fopen(filename, "w+")) { if (m_file_handle == NULL) throw openError(); } File::~File() { std::fclose(m_file_handle); }
  • 44. void ExampleWithRAII() { // open file (acquire resource) File* logFile = new File("logfile.txt"); logFile->Write("Hello, Log File!"); // continue writing to logfile.txt ... } File::File(const char* filename) : m_file_handle(std::fopen(filename, "w+")) { if (m_file_handle == NULL) throw openError(); } File::~File() { std::fclose(m_file_handle); }
  • 45. 다시 발생하는 문제 • 파일 입출력과 관련한 예외 처리를 간편하게 하기 위해 File 클래스를 만들어 생성자와 소멸자로 처리했다. • 하지만, 정작 File 클래스를 동적으로 할당하는 경우 소멸자가 호출되지 않아 파일을 닫지 않는 문제가 발생한다. • 좋은 방법이 없을까? → 스마트 포인터(Smart Pointer)의 등장!
  • 46. 스마트 포인터 • 좀 더 똑똑한 포인터 • 스마트 포인터를 사용하면 명시적으로 해제할 필요가 없다. • 사용하는 이유 • 적은 버그, 자동 청소, 자동 초기화 • Dangling 포인터 발생 X, Exception 안전 • 효율성
  • 47. void ExampleWithRAII() { // open file (acquire resource) std::unique_ptr<File> logFile = std::make_unique<File>("logfile.txt"); logFile->Write("Hello, Log File!"); // continue writing to logfile.txt ... } File::File(const char* filename) : m_file_handle(std::fopen(filename, "w+")) { if (m_file_handle == NULL) throw openError(); } File::~File() { std::fclose(m_file_handle); }
  • 48. 스마트 포인터의 종류 • 경우에 따라 여러 종류의 스마트 포인터를 사용할 수 있다. • shared_ptr : 객체의 소유권을 복사할 수 있는 포인터 (여러 shared_ptr 객체가 같은 포인터 객체를 가리킬 수 있음) • unique_ptr : 객체의 소유권을 복사할 수 없는 포인터 (하나의 unique_ptr 객체만이 하나의 포인터 객체를 가리킬 수 있음)
  • 49. std::unique_ptr ptrA Song 개체 ptrA Song 개체 ptrB auto ptrA = std::make_unique<Song>(L"Diana Krall", L"The Look of Love"); auto ptrB = std::move(ptrA);
  • 50. std::unique_ptr<Song> SongFactory(const std::wstring& artist, const std::wstring& title) { // Implicit move operation into the variable that stores the result. return std::make_unique<Song>(artist, title); } void MakeSongs() { // Create a new unique_ptr with a new object. auto song = std::make_unique<Song>(L"Mr. Children", L"Namonaki Uta"); // Use the unique_ptr. std::vector<std::wstring> titles = { song->title }; // Move raw pointer from one unique_ptr to another. std::unique_ptr<Song> song2 = std::move(song); // Obtain unique_ptr from function that returns by value. auto song3 = SongFactory(L"Michael Jackson", L"Beat It"); }
  • 51. std::shared_ptr MyClass 제어 블록 참조 개수 = 1 개체에 대한 포인터 제어 블록에 대한 포인터 p1
  • 52. std::shared_ptr MyClass 제어 블록 참조 개수 = 2 개체에 대한 포인터 제어 블록에 대한 포인터 p1 개체에 대한 포인터 제어 블록에 대한 포인터 p2
  • 53. // Use make_shared function when possible. auto sp1 = std::make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You"); // Ok, but slightly less efficient. // Note: Using new expression as constructor argument // creates no named variable for other code to access. std::shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance")); // When initialization must be separate from declaration, e.g. class members, // initialize with nullptr to make your programming intent explicit. std::shared_ptr<Song> sp5(nullptr); //Equivalent to: shared_ptr<Song> sp5; //... sp5 = std::make_shared<Song>(L"Elton John", L"I'm Still Standing");
  • 54. 리소스 관리는 스마트 포인터로 • RAII를 사용하자! • 읽고, 쓰고, 유지보수하기 쉽다. • 자원 관리에 대한 걱정을 할 필요가 없다. • C++ 코드 품질을 향상시키는 가장 쉬운 방법! • 기왕이면 스마트 포인터로! • shared_ptr • unique_ptr
  • 56. std::vector<int>::const_iterator iter = cardinal.begin(); std::vector<int>::const_iterator iter_end = cardinal.end(); int total_elements = 1; while (iter != iter_end) { total_elements *= *iter; ++iter; }
  • 57. template <typename T> struct product { product(T& storage) : value(storage) {} template<typename V> void operator()(V& v) { value *= v; } T& value; }; std::vector<int> cardinal; int total_elements = 1; for_each(cardinal.begin(), cardinal.end(), product<int>(total_elements));
  • 58. int total_elements = 1; for_each(cardinal.begin(), cardinal.end(), [&total_elements](int i) { total_elements *= i; });
  • 59. struct mod { mod(int m) : modulus(m) {} int operator()(int v) { return v % modulus; } int modulus; }; int my_mod = 8; std::transform(in.begin(), in.end(), out.begin(), mod(my_mod)); int my_mod = 8; transform(in.begin(), in.end(), out.begin(), [my_mod](int v) -> int { return v % my_mod; }); Functor Lambda Expression
  • 60. 람다식 [my_mod] (int v) -> int { return v % my_mod; } 개시자 (Introducer Capture) 인자 (Arguments) 반환 타입 (Return Type) 함수의 몸통 (Statement)
  • 61. int x = 10, y = 20; [] {}; // capture 하지 않음 [x] (int arg) { return x; }; // value(Copy) capture x [=] { return x; }; // value(Copy) capture all [&] { return y; }; // reference capture all [&, x] { return y; }; // reference capture all except x [=, &y] { return x; }; // value(Copy) capture all except y [this] { return this->something; }; // this capture [=, x] {}; // error [&, &x] {}; // error [=, this] {}; // error [x, x] {}; // error
  • 62. 1 2 2 void fa(int x, function<void(void)> f) { ++x; f(); } void fb(int x, function<void(int)> f) { ++x; f(x); } void fc(int &x, function<void(void)> f) { ++x; f(); } int x = 1; fa(x, [x] { cout << x << endl; }); fb(x, [](int x) { cout << x << endl; }); fc(x, [&x] { cout << x << endl; });
  • 63. WNDCLASSEX wcex; wcex.lpfnWndProc= [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT { switch (message) { case WM_COMMAND: EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL { char szText[256]; GetWindowTextA(hwnd, szText, 256); cout << szText << endl; return TRUE; }, 0);
  • 64. HANDLE hT = CreateThread(NULL, 0, [](LPVOID lpThreadParameter) -> DWORD { for (int i = 0; i < 1000; i++) { this_thread::sleep_for(milliseconds{ 10 }); cout << i << endl; } return 0; }, NULL, 0, NULL);
  • 65. 람다식을 사용하자 • 짧고, 간결하고, while 문과 같은 행사 코드 없이 깔끔하게 작성할 수 있다. • 수십줄의 코드를 1~2줄로 간추릴 수 있다. • Functor, Callback Function을 대체해서 사용할 수 있다. • 반복적으로 사용하는 함수가 아니라면 람다식을 사용하자!
  • 67. auto 키워드 • 컴파일 타임에 타입을 추론해 어떤 타입인지 결정한다. • 컴파일 타임에 추론이 불가능하다면, 오류가 발생한다. std::vector<std::tuple<std::string, int, double>> vStudents; for (std::vector<std::tuple<std::string, int, double>>::iterator iter = vStudents.begin(); iter != vStudents.end(); ++iter) { … } std::vector<std::tuple<std::string, int, double>> vStudents; for (auto iter = vStudents.begin(); iter != vStudents.end(); ++iter) { … }
  • 68. 범위 기반 for문 int arr[] = { 1, 2, 3, 4, 5 }; for (int i = 0; i < 5; ++i) std::cout << arr[i] << std::endl; return 0; } int arr[] = { 1, 2, 3, 4, 5 }; for (auto& i : arr) std::cout << i << std::endl; return 0; }
  • 69. 정리 // circle and shape are user-defined types circle* p = new circle(42); vector<shape*> v = load_shapes(); for (vector<circle*>::iterator i = v.begin(); i != v.end(); ++i) { if (*i && **i == *p) cout << **i << " is a matchn"; } for (vector<circle*>::iterator i = v.begin(); i != v.end(); ++i) { delete *i; // not exception safe } delete p;
  • 70. 정리 // circle and shape are user-defined types auto p = make_shared<circle>(42); vector<shared_ptr<shape>> v = load_shapes(); for_each(begin(v), end(v), [&](const shared_ptr<shape>& s) { if (s && *s == *p) cout << *s << " is a matchn"; });
  • 71. 정리 • 대체할 수 있는 조건부 컴파일은 템플릿으로 기름칠! • 매크로는 가급적 사용하지 말고 열거체와 함수로 기름칠! • 리소스 관리에는 RAII, 기왕이면 스마트 포인터로 기름칠! • 일회성으로 사용하는 함수는 람다식으로 기름칠! • 복잡한 타입에는 auto로 기름칠! • 반복 횟수에 고통받지 말고 범위 기반 for문으로 기름칠!
  • 72. 정리 • 모던 C++을 통해 대체할 수 있는 코드는 많습니다! (하지만 제한된 시간으로 인해 …) • 다음 사이트에서 모던 C++ 예제 코드를 확인하실 수 있습니다. http://www.github.com/utilForever/ModernCpp • C++ 핵심 가이드라인 • 영문 : https://github.com/isocpp/CppCoreGuidelines • 한글 : https://github.com/CppKorea/CppCoreGuidelines
  • 73. Quiz
  • 74. #include <iostream> #include <memory> #include <vector> class C { public: void foo() { std::cout << "A"; } void foo() const { std::cout << "B"; } }; struct S { std::vector<C> v; std::unique_ptr<C> u; C* const p; S() : v(1), u(new C()), p(u.get()) {} }; Quiz #1 int main() { S s; const S& r = s; s.v[0].foo(); s.u->foo(); s.p->foo(); r.v[0].foo(); r.u->foo(); r.p->foo(); } AAABAA
  • 75. #include <iostream> struct A { A() { std::cout << "A"; } A(const A& a) { std::cout << "B"; } virtual void f() { std::cout << "C"; } }; int main() { A a[2]; for (auto x : a) { x.f(); } } Quiz #2 AABCBC
  • 76. #include <iostream> struct A { A() { std::cout << "A"; } A(const A& a) { std::cout << "B"; } virtual void f() { std::cout << "C"; } }; int main() { A a[2]; for (auto& x : a) { x.f(); } } Quiz #3 AACC
  • 78. 감사합니다. • MSDN Forum http://aka.ms/msdnforum • TechNet Forum http://aka.ms/technetforum
  • 79. http://aka.ms/td2015_again TechDays Korea 2015에서 놓치신 세션은 Microsoft 기술 동영상 커뮤니티 Channel 9에서 추후에 다시 보실 수 있습니다.