52
Effective Modern C++ Study C++ Korea

[C++ Korea] Effective Modern C++ Study item14 16 +신촌

Embed Size (px)

Citation preview

Page 1: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

Page 2: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 3: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 4: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

try {

if (/* Exception Condition */)

throw new std::exception("Error Description");

}

catch (std::exception e)

{

cout << "Exception : " << e.what() << endl;

}

4

예외가 발생할 수 있는 부분을 정의

try { } 와 catch { } 는 한쌍

예외를 발생시킴

try 안에서 발생한 예외 중 e를 catch

예외 처리

Page 5: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 5

• void func(int a)

• void func(int a) throw(int);

• void func(int a) throw(char *, int);

• void func(int a) throw();

모든 타입의 예외가 발생 가능하다.

int 타입 예외를 던질 수 있다.

타입이 2가지 이상일 경우는 , 로 나열

예외를 발생하지 않는다.

Page 6: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 6

void f1() { throw 0; }

void f2() { f1(); }

void f3() { f2(); }

void f4() { f3(); }

void main()

{

try

{

f4();

}

catch (int e)

{

std::cout << e << std::endl;

}

}

예외 처리를 하기 위해 발생 시점부터 처리하는 위치까지 Stack에서 함수를 소멸시키면서 이동

함수 호출

스택 풀기

http://devluna.blogspot.kr/2015/02/c-exception-handling.html

Page 7: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 8: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 8

사용자는 자신이 사용 하는 함수의 발생 가능한 예외들에 대해서 알고 있어야 한다.

하지만 C++에서는 상당히 귀찮은 일이고 그 동안 잘 안 했었다.

기껏해야 예외를 발생하지 않을 경우만 명시적으로 선언해주는 친절한 사람도

간혹 있긴 하더라고 누군가 말하는걸 얼핏 들은 적이라도 있나 ?

(난 없음)

int f(int x) throw(); // C++98 Style

int f(int x) noexcept; // C++11 Style

Page 9: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 9

• C++98 Style : 스택 풀기(Stack unwinding)을 시도

• C++11 Style : 스택 풀기를 프로그램 종료전에 할 수도 있다.

(gcc는 하지않고 종료, Clang은 종료전에 스택 풀기 수행)

• noexcept를 쓰면 예외가 전파되는 동안 Runtime 스택을 유지할 필요도 없고,

함수내 생성한 객체도 순서에 상관없이 소멸이 가능하다.

int f(int x) noexcept; // most optimizable

int f(int x) throw(); // less optimizable

int f(int x); // less optimizable

Page 10: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 10

• Push를 하려는데 내부 버퍼가 꽉찼다면 ?

1. 크기를 2배로 확장

2. Data COPY

3. 기존 공간 삭제

4. 객체가 가리키는 주소 변경

std::vector<Widget> vw;

Widget w;

vw.push_back(w);

• 어~~~~ 그런데~~~~~

COPY 중 오류가 나면 ???

1. 그냥 기존꺼 쓰면 되지머.

2. 끝 !

Page 11: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 11

• Push를 하려는데 내부 버퍼가 꽉찼다면 ?

1. 크기를 2배로 확장

2. Data MOVE

3. 기존 공간 삭제

4. 객체가 가리키는 주소 변경

• 어~~~~ 그런데~~~~~

MOVE 중 오류가 나면 ???

1. 다시 원래대로 MOVE 하자.

• 어~ 다시 MOVE 하는데 오류가 ?

아놔~

std::vector<Widget> vw;

Widget w;

vw.push_back(w);

Page 12: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 12

• 그럼 MOVE 하지 말고 C++ 98 Style로 COPY를 ?

• 예외가 안 일어난다고 확인된 것만 MOVE 하자.

• 예외가 일어날지 안 일어날지는 어떻게 알고 ?

• noexcept 라고 선언된 것만 MOVE 하자.

Page 13: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 13

noexcept(bool expr = true)

template <class T, size_t N>

void swap(T(&a)[N],

T(&b)[N]) noexcept(noexcept(swap(*a, *b)));

template <class T1, class T2>

struct pair {

...

void swap(pair& p) noexcept(noexcept(swap(first, p.first)) &&

noexcept(swap(second, p.second)));

... };

배열의 각 요소들의 swap이

noexcept인 경우 해당 함수도

noexcept

pair의 각 요소들의 swap이

noexcept인 경우 해당 함수도

noexcept

Page 14: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 15: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 15

noexcept는 심사 숙고해서 사용하자.

noexcept로 선언한 함수를 수정하였는데 예외가 발생할 수 있게 되었다면 ???

noexcept지우면 되지머.

그럼 noexcept라고 믿고 해당 함수를 쓴 code들은 ???

흠… 난리나겠네. ;;;;

예외가 안나오도록 안에서 어떻게든 다 처리하지머.

noexcept를 쓰는 이유가 성능상 이익을 보기 위해서인데… 이러면…

아고… 의미없다.

그럼 예외가 아니라 return값으로 error code들을 처리하면 ???

성능상 이익이라고 아까 말했는데, 이러면 함수를 사용한 쪽에서 다시 해석을 해야하고…

Page 16: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 16

• default로 noexcept 의 특성을 가지는 대표적인 예

• 멤버 변수의 소멸자가 모두 noexcept일 경우 자동으로 noexcept로 처리

(STL내에는 예외 발생 가능한 소멸자는 없다.)

• 예외가 발생할 수 있을 경우는 명시적으로 noexcept(false)로 선언

Page 17: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 17

• Wide contracts : 함수 호출 전 사전 조건이 없음

void f(const std::string& s) noexcept; // precontidion : s.length() <= 32

• Narrow contracts : 함수 호출 전 사전 조건이 있음

Precondition violation exception 을 발생시켜야 한다.

Page 18: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 18

void setup();void cleanup();

void init() noexcept

{

setup();

// do something

cleanup();

} • C-Style 함수 • C++98 이전에 개발된 함수 일수도 있으므로, noexcept 여부를 Check하지 않는다.

noexcept 선언이 없는데…

Page 19: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 20: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 20

• noexcept는 함수 인터페이스에 속한다. 해당 함수 사용자는 noexcept 여부에 대해서 알아야 한다.

• noexcept로 함수를 선언하면 성능상의 이점을 볼 수 있다.

• move 연산, swap, 메모리 해제 함수, 소멸자 등에서의 noexcept 여부는 아주 중요하다.

• 대부분의 함수들은 noexcept로 선언하지 않고 예외를 처리하는 함수로 선언하는게 더 자연스럽다.

Page 22: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 24: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 24

struct S { static const int size; }; const int limit = 2 * S::size; // dynamic initialization const int S::size = 256; const int z = numeric_limits::max(); // dynamic initialization

Page 25: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 25

Page 26: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

int sz; // non-constexpr variable

constexpr auto arraySize1 = sz; // error! sz's value not

// known at compilation

std::array<int, sz> data1; // error! same problem

constexpr auto arraySize2 = 10; // fine, 10 is a compile-time // constant

std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr

const auto arraySize = sz; // fine, arraySize is const copy

// of sz

std::array<int, arraySize> data; // error! arraySize's value not

// known at compilation

26

Page 27: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 27

Page 28: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

constexpr // pow's a constexpr func

int pow(int base, int exp) noexcept // that never throws

{

… // impl is below

}

constexpr auto numConds = 5; // # of conditions

std::array<int, pow(3, numConds)> results; // results has 3^numConds elements

28

Page 29: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

auto base = readFromDB("base"); // get these values

auto exp = readFromDB("exponent"); // at runtime

auto baseToExp = pow(base, exp);

// call pow function at runtime

29

Page 30: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

30

constexpr int pow(int base, int exp) noexcept

{

return (exp == 0 ? 1 : base * pow(base, exp - 1));

}

Page 31: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

constexpr int next(int x)

{ return ++x; }

constexpr int twice(int x);

enum { bufsz = twice(256) };

constexpr int fac(int x)

{ return x > 2 ? x * fac(x - 1) : 1; }

extern const int medium;

const int high = square(medium);

31

Page 32: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 32

constexpr int pow(int base, int exp) noexcept // C++14

{

auto result = 1;

for (int i = 0; i < exp; ++i) result *= base;

return result;

}

Page 33: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 33

class Point {

public:

constexpr Point(double xVal = 0, double yVal = 0) noexcept

: x(xVal), y(yVal) {}

constexpr double xValue() const noexcept{ return x; }

constexpr double yValue() const noexcept{ return y; }

void setX(double newX) noexcept{ x = newX; }

void setY(double newY) noexcept{ y = newY; }

private:

double x, y;

};

Page 34: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 34

class Point {

public:

constexpr void setX(double newX) noexcept // C++14

{ x = newX; }

constexpr void setY(double newY) noexcept // C++14

{ y = newY; }

};

- Constexpr은 const임을 암시하기 때문에 의미 상 setter는 부자연스러움, 그러나 C++14에서는 이를 허용

- Return 값이 void인 것을 허용하지 않았으나 가능해짐

Page 35: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 35

// return reflection of p with respect to the origin (C++14)

constexpr Point reflection(const Point& p) noexcept

{

Point result; // create non-const Point

result.setX(-p.xValue()); // set its x and y values

result.setY(-p.yValue());

return result; // return copy of it

}

constexpr Point p1(9.4, 27.7); // as above

constexpr Point p2(28.8, 5.3);

constexpr auto mid = midpoint(p1, p2);

constexpr auto reflectedMid = // reflectedMid's value is

reflection(mid); // (-19.1 -16.5) and known during compilation

Page 36: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 36

Page 37: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 38: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 39: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 39

Page 40: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 40

Page 41: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 42: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 42

Page 43: [C++ Korea] Effective Modern C++ Study item14 16 +신촌
Page 44: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 44

Page 45: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 45

S :

Thread 1 Thread 2

Newton-lapsen Algorithm Executed double-time.

Page 46: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 46

Locking…

Page 47: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 47

Page 48: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 48

생성자에 lock,

소멸자에 unlock

Page 49: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 49

atomic을 이용하면 p_type의 연산 순서를 보증할 수 있다.

Page 50: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea 50

Page 51: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

51

Page 52: [C++ Korea] Effective Modern C++ Study item14 16 +신촌

Effective Modern C++ Study C++ Korea

• const member function도 thread-safe가 필요하다.

• 단일 변수 공유시에는 std::atomic을 이용하자.