Api design for c++ 6장

36
6. C++의 올바른 사용 API design for C++ 1 김지훈 아꿈사 2014. 02. 15.

Transcript of Api design for c++ 6장

Page 1: Api design for c++ 6장

6장. C++의올바른사용API design for C++

1

김지훈아꿈사

2014. 02. 15.

Page 2: Api design for c++ 6장

이번장은

대체로 C++의문법적측면의내용(pass)

C++을쓰면서놓치기쉬운 부분

API 제작시특히유의할부분

2

Page 3: Api design for c++ 6장

네임스페이스

접두어

glBegin(), GL_BLEND_COLOR, QWidget …

namespace 키워드

namespace MyAPI {

class String {

public: String();

....

}

}

3

Page 4: Api design for c++ 6장

네임스페이스

이름공간분리이름충돌방지

추상화도구

이름을연관된것끼리모음

4

Page 5: Api design for c++ 6장

생성자와할당연산자

The Big Three

소멸자, 복사생성자, 할당연산자

이중하나를정의하면일반적으로나머지도따라온다.

기본생성함수제어 (C++11)class NonCopyable {

public:

NonCopyable() = default;

NonCopyable(const NonCopyable&) = delete;

NonCopyable& operator = (const NonCopyable&) = delete;

};

5

Page 6: Api design for c++ 6장

const 메서드

객체의상태를변경하지않음을명시

논리적관점에서변화가없는경우변경할수도있음

mutable 키워드

6

Page 7: Api design for c++ 6장

mutable 키워드

Class HashTable{

public:

void Insert(const std::string &str);

int Remove(const std::string &str);

bool Has(const std::string &str) const;

int GetSize() const;

. . .

private:

int mCachedSize;

bool mSizeIsDirty;

};

7

int HashTable::GetSize() const {

// 성능을위해캐싱

if (mSizeIsDirty)

{

// Error!!

mCachedSize = CalculateSize();

mSizeIsDirty = false;

}

return mCachedSize;

}

Page 8: Api design for c++ 6장

mutable 키워드

Class HashTable{

public:

void Insert(const std::string &str);

int Remove(const std::string &str);

bool Has(const std::string &str) const;

int GetSize() const;

. . .

private:

mutable int mCachedSize;

mutable bool mSizeIsDirty;

};

8

int HashTable::GetSize() const {

// 성능을위해캐싱

if (mSizeIsDirty)

{

// OK!

mCachedSize = CalculateSize();

mSizeIsDirty = false;

}

return mCachedSize;

}

Page 9: Api design for c++ 6장

const 파라미터

std::string StringToLower(std::string &str);

str은 input 인가 output 인가?

Google c++ style guide

std::string StringToLower(const std::string &str); input parameter

std::string StringToLower(std::string* str); output parameter

9

Page 10: Api design for c++ 6장

const 리턴값

// return by value

std::string GetName() const

{

return mName;

}

// return by const reference

const std::string &GetName() const

{

return mName;

}

10

리턴값이객체의내부를변경할수없으므로안전

더나은성능필히 const 선언필요리턴된값의수명주기확인필요

가급적 return by value를이용하자

Page 11: Api design for c++ 6장

template

template <typename T>

class Stack {

public:

void Push(T val);

T Pop();

bool IsEmpty() const;

private:

std::vector<T> mStack;

};

11

Stack<int> int_stack;int_stack.Push(1);int_stack.Push(2);int_stack.Push(3);

Stack<std::string> str_stack;str_stack.Push("123");str_stack.Push("456");

Page 12: Api design for c++ 6장

암시적인스턴스화

헤더파일에템플릿클래스의 구현코드를모두포함

API 사용자가원하는어떤타입이라도인스턴스화할수있음

구현소스가헤더에모두노출됨

12

Page 13: Api design for c++ 6장

암시적인스턴스화

소스의노출을최소화하기위해헤더가아닌별도의파

일에구현

13

// stack_priv.htemplate<typename T>T Stack<T>::Pop() {

...}

// stack.h

template<typename T>

class stack {

T Pop();

...

};

#include "stack_priv.h”

Page 14: Api design for c++ 6장

명시적인스턴스화

API개발자가미리지정해둔타입만생성가능

14

// stack.h

template<typename T>

class stack {

T Pop();

...

};

// stack.cpptemplate<typename T>T Stack<T>::Pop() {

...}

// 명시적인스턴스화template class Stack<int>;template class Stack<double>;template class Stack<std::string>;

Page 15: Api design for c++ 6장

명시적인스턴스화

컴파일타임감소

구현코드숨김

extern template (C++11)

15

Page 16: Api design for c++ 6장

extern template

16

// header.htemplate<typename T> void ReallyBigFunction() { // Body }

// source1.cpp#include "header.h"void something1() { ReallyBigFunction<int>(); }

// source2.cpp#include "header.h"void something2() { ReallyBigFunction<int>(); }

source1.o void something1() void ReallyBigFunction<int>() // Compiled first time

source2.o void something2() void ReallyBigFunction<int>() // Compiled second time <- 중복컴파일!

Page 17: Api design for c++ 6장

extern template

17

source1.o void something1() void ReallyBigFunction<int>() // Compiled first time

source2.o // No ReallyBigFunction<int> here because of the extern

// source2.cpp#include "header.h“

extern template ReallyBigFunction<int>(); void something2() { ReallyBigFunction<int>(); }

컴파일타임감소

오브젝트사이즈감소

// 현재오브젝트에서인스턴스화금지

정적 lib 형태로라이브러리배포할때 lib안에서쓰면유용할듯

Page 18: Api design for c++ 6장

함수기본파라미터의단점

class Circle {public:

Circle(double x = 0, double y = 0, double radius = 10.0);. . .

};

Circle c1();Circle c2(2.3);Circle c3(2.3, 5.6); Circle c4(2.3, 5.6, 1.5);

18

// x만입력하고 y는없는논리적모순// 반지름이변경되면 Client Code 재컴파일필요

Page 19: Api design for c++ 6장

기본값대신함수오버로드

class Circle {

public:

Circle();

Circle(double x, double y); // 반지름정보가 cpp에숨겨짐

Circle(double x, double y, double radius);

. . .

};

19

Page 20: Api design for c++ 6장

#DEFINE 상수사용금지

#define MORPH_FADEIN_TIME 0.3f

#define MORPH_IN_TIME 1.1f

#define MORPH_FADEOUT_TIME 1.4f

20

Page 21: Api design for c++ 6장

#DEFINE 상수사용금지

타입이없음

#define MAX_VALUE 1 // 정수형

#define MAX_VALUE 1f // 부동소수형

실수의여지가있음

21

Page 22: Api design for c++ 6장

#DEFINE 상수사용금지

범위가없음

#define max(a, b) a > b ? a : b

class Array {public:

Array();int max(); // Compile error!...

}

전역네임스페이스를오염시킴

22

Page 23: Api design for c++ 6장

#DEFINE 상수사용금지

접근제어불가능

public, protected, private 설정안됨

항상 public

심볼이없음

매크로는전처리과정에서사라지기때문에디버깅어려움

23

Page 24: Api design for c++ 6장

상수변수를사용하자

class Morph {

public:

static const float FadeInTime;

static const float InTime;

static const float FadeOutTime;

. . .

};

float fade_in_time = Morph::FadeInTime;

24

Page 25: Api design for c++ 6장

enum을사용

#define LEFT_JUSTIFIED 0

#define RIGHT_JUSTIFIED 1

#define CENTER_JUSTIFIED 2

#define FULL_JUSTIFIED 3

enum JustificationType {LEFT_JUSTIFIED,RIGHT_JUSTIFIED,CENTER_JUSTIFIED,FULL_JUSTIFIED

};

25

Page 26: Api design for c++ 6장

friend 사용금지

class Node {

public:

. . .

friend class Graph;

private:

void ClearVisited();

void SetVisited();

bool IsVisited() const;

. . .

bool is_visited;

};

#include "node.h"

// 이름이같은별도의 Graph 클래스

Class Graph {

public:

void ViolateAccess(Node *node) {// Graph는 node의 friend이므로

// private 멤버호출가능

node ->SetVisited();

}

};

26

Page 27: Api design for c++ 6장

friend 사용금지

캡슐화의구멍을허용함 (여기까지저자의생각)

반면,

인터페이스는전역에공개되지만 friend는한정된공개이므로더

캡슐화될수도있음.

27

Page 28: Api design for c++ 6장

friend는정말나쁜가

class Node {

public:

. . .

friend class Graph;

private:

void ClearVisited();

void SetVisited();

bool IsVisited() const;

. . .

};

#include "node.h"

Class Graph {

public:

void ViolateAccess(Node *node) {

if (node -> IsVisited ()) {

……

}

}

};

28

Page 29: Api design for c++ 6장

friend는정말나쁜가

class Node {

public:

. . .

friend class Graph;

bool IsVisited() const; // 전역공개

private:

void ClearVisited();

void SetVisited();

bool IsVisited() const;

. . .

};

#include "node.h"

Class Graph {

public:

void ViolateAccess(Node *node) {

if (node -> IsVisited ()) {

……

}

}

};

29

Page 30: Api design for c++ 6장

더나은구조

#include "node.h"

// 이름이같은별도의 Graph 클래스

Class Graph {

public:

void ViolateAccess(Node *node) {

if (visited_nodes_.find(node) != visited_nodes_.end()) {

……

}

}

std::set<Node *> visited_nodes_;

};30

Page 31: Api design for c++ 6장

꼭나쁘기만한건없다

a : 어차피멤버에접근이필요하다면 get/set 보다낫지않냐?

b : 하지만애초에그럴수밖에없는구조가나쁜건아닐까?

a : 그럼구조를뒤집어야되는데?

더나쁜설계에서더좋은설계로개선해가는리펙토링의

중간단계로서의미는있음. (개인적의견)

31

Page 32: Api design for c++ 6장

CPP도안전하지않다

// xxx.cpp. . .const int INTERNAL_CONSTANT 42;std::string Filename = "file.txt";void FreeFunction(){

std::cout << "Free function called" << std::endl;}const int MAX_VALUE = 100;. . .

32

Page 33: Api design for c++ 6장

CPP도안전하지않다

// 우리라이브러리를가져다쓰는 Client Code.cpp

extern void FreeFunction();extern const int INTERNAL_CONSTANT;extern std::string Filename;

FreeFunction();std::cout << "Constant " << INTERNAL_CONSTANT << std::endl;Filename = "different.txt";

// 추가로이름충돌문제도있음.

const int MAX_VALUE = 100; // link time error!! (이름중복)

33

Page 34: Api design for c++ 6장

CPP도안전하지않다

정적선언// library cpp

static const int INTERNAL_CONSTANT 42;

static std::string Filename = “file.txt”;

static void FreeFunction() { …}

익명네임스페이스namespace {

const int INTERNAL_CONSTANT 42;std::string Filename "file.txt";void FreeFunction() {

std::cout << "Free function called" << std::endl;}

}34

Page 35: Api design for c++ 6장

코딩규칙

C++은강력하지만아주복잡

C++을잘활용하려면필요한만큼언어의기능을제약해야함복잡하지만쓰고싶은만큼덜어쓸수있는게장점

코딩규칙의첫번째는일관성

google c++ style guide

35

Page 36: Api design for c++ 6장

Refference

API design for C++, Martin Reddy

template : http://stackoverflow.com/questions/8130602/using-extern-

template-c0x

friend : http://ikpil.com/1036

36