NDC/Server

[NDC 2016] 테라 서버의 Modern C++ 활용기

MAKGA 2023. 1. 14. 18:34
320x100

smart pointer (RAII)

- 객체의 생성 소멸 관리를 위해 사용하는 객체

- shared_ptr<T>, unique_ptr<T>

 

t_ptr<T>

- shared_ptr<T>처럼 Reference Count를 공유

- 침습형(invasive) 카운터를 사용

 

 

Cppcon2015 중

"Smart pointers" are overused (스마트 포인터는 과다 사용되고 있다)

- shared_ptr can be expensive => reference count의 증감 연산이 많이 일어나기 때문에

 

사례1) 빠른줄만 알았던 type_cast

template<typename T, typename S>
T* type_cast<T>(S* s)
{
    if (s && TypeTable<Idx<S>][Idx<T>])
    {
        return static_cast<T>(s);
    }

    return nullptr;
}


template<typename T, typename S>
t_ptr<T> type_cast<T>(t_ptr<S> s)
{ <29.9%
    if (s && TypeTable<Idx<S>][Idx<T>])
    {
        return static_cast<T>(s);
    } <70.0%

    return nullptr;
}

// 뜻 밖의 복사생성자와 소멸자가 호출
// t_ptr<S>와 t_ptr<T>를 & 또는 && 형으로 변경

 

사례 2) 빠른줄만 알았던 Vector

주위에 있는 GameObject의 t_ptr을 Vector에 저장하는데 느려진다 => Reallocation에서 RefCount++/--가 일어나는걸 확인

 

Vector Reallocation (push_back)

이를 방지하기 위해 Move Semantics 사용

생성자난 대입연산자가 Rvalue를 사용할 땐 '소유권'을 넘겨주는 것만으로 충분하다

Object(Object&& other) {
    mChile = other.mChild;
    other.mChild = nullptr;
}

Object(Object& other) {
    DeepCopy(mChild, other.mChild);
}

 

 

 

variadic template and some practical techniques (변수 템플릿과 몇 가지 실용적인 기술)

Variadic Template

- 임의의 인자 개수를 지원하는 템플릿 형식(클래스, 함수 모두 지원)

- Ellipsis operator(...)와 함께 사용 => arguments, paramters, sizeof op, initializer list of array, member initializer list, lambda capture, exception specification list

먼 과거

template<class Type, class Arg1, class Arg2, class Arg3>
Type* tnew(Arg1 arg1, Arg2 arg2, Arg3, arg3)
{
    Type* memory = (Type*)AllocMemory(sizeof(Type));
    new(memory) Type(arg1, arg2, arg3);
    return (Type*)memory;
}

과거

#define MEMORY_ALLOC_ARG_NUM 40
#define MEORY_tnew_print(z, n, _) \
template<class Type BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class Arg)> \
Type* tnew(BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, arg)) \
{ \
    Type* memory = (Type*)AllocMemory(sizeof(Type)); \
    new(memory) Type(BOOST_PP_ENUM_PARAMS(n, arg));\
    return memory; \
} \
BOOST_PP_REPEAT(BOOST_PP_INC(MEMORY_ALLOC_ARG_NUM(, MEMORY_tenw_print, _)

현재

template<class Type, class... Args>
Type* tnew(Args&&... args)
{
    Type* memory = (Type*)AllocMemory(sizeof(Type));
    new(memory)Type(forward<Args>(args)...);
    return memory;
}

 

 

튜플의 각 원소들에 대해서 함수를 수행하고 싶고, 함수의 인자로도 사용하고 싶다

Integer_sequence

template<int... Remains>
struct req{};

template<int N, int... Remains>
struct gen_seq : gen_seq <N-1, N-1, Remains...> {};

template<int N, int... Remains>
struct gen_seq<0, Remains...> : seq <Remains...> {};

gen_seq<3> -> <2, 2> -> <1, 1, 2> -> <0, 0, 1, 2> -> seq<0, 1, 2>

* C++14부턴 간단하게 std::make_index_sequence<N>으로 대체 가능

 

 

 

C++ 11/14 비동기 키워드

std::thread

std::thread t(&func, 3);
std::thread t2([] { printf("f"); });
t.join();
t2.join();

std::promise / std::future

promise<int> prom;
future<int> fut = prom.get_future();
auto t = thread[&]{ prom.set_value(1); });

cout << fut.get << endl;
t.join();

std::async

auto myFuture = async(launch::async, &foo, 1.0);
cout << myFuture.get() << endl;
// original
bool result = true;
for (auto& job : jobList) {
    if (job.Execute() == false)
        return = false;
}

// distribution
bool result = true;
vector<future<bool>> futures;
for (auto& job : jobList) {
    futures.push_back(
        async(lanuch:async, [&] { job.Execute(); }));
}

for (const auto& fut : futures) {
    if (fut.get() == false)
        result = false;
}

출처: http://ndcreplay.nexon.com/NDC2016/sessions/NDC2016_0066.html

320x100