반응형
반응형

1. 클로저(C++예시)

2. 람다 expression(C++11 부터)

  1. 람다 표현식이란?

    • 이름이 없는 함수 객체를 만드는 방법

    • 람다 표현식과 Functor(함수 객체)의 어셈블리 코드는 동일함

  2. 형식

    • auto lambda = [localv=3](int a){
      return a + localv;
      }
    • 캡쳐 : [] 안에 들어가는 부분
class Plus{
public:
   explicit Plus(int a) : localVar{a} {}
   int operator() (int x) const{
      return localVar + x;
   }
private:
   int localVar;
}

int main(){
   auto lambdaPlus3 = [localVar=3](int x){
      return localVar + x;
   }

   Plus plus3{3};

   std::cout << plus3(10) << std::endl;
   std::cout << lambdaPlus3(10) << std::endl;
   // 위의 결과 및 어셈블리 코드는 동일함
}

3. 캡쳐

  1. 값에 의한 캡쳐
    • [localv] 또는 [=]
    • 함수 객체의 멤버 변수와 같은 역할
    • [localv] : 위에서 localv 변수를 찾아 람다 내부에서 사용
    • [=] 만 쓰면 람대 내부에 사용된 변수를 위에서 찾아 자동으로 값에 의한 캡쳐를 함
int three{3};
auto lambdaPlus3 = [=](int x){
   return x + three;
// 위에서 three를 찾아 값에 의한 캡쳐를 함
};
  1. 참조에 의한 캡쳐

    • 함수 객체의 참조 멤버 변수와 같은 역할
    • 전달하는 객체가 큰 경우 사용
    • [&] 만 쓸 경우 람대 내부에 사용된 변수를 위에서 찾아 자동으로 참조에 의한 캡쳐를 함
  2. this에 의한 캡쳐

    • [this]
    • 멤버 변수와 함수를 람대 내부에서 사용 가능함!
class Cat{
public:
   explicit Cat(int age) : mAge{age} {}
   void speak() const {}
   void test() const {
      auto lambda = [this](){
         this->mAge;
         this->speak();
      }
      lambda();
   }
private:
   int mAge;

int main(){
   Cat kitty(3);
   kitty.test();
}

4. 람다 표현식 + STL 함수 사용 예제

vector<int> nums{1,2,3,4,5,6,7,8,9,10};
auto lambdaAdd10 = [](int &n){
   n += 10;
}

for_each(nums.begin(), nums.end(), lambdaAdd10);
// nums 의 인자에 모두 10을 더함
// nums = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20}

5. 고차원 함수란

  1. 함수를 인자로 받음
  2. 함수를 리턴함

6. 함수형 프로그래밍

  1. 함수를 변수나 객체처럼 다룰 수 있다.
  2. std::function 사용 시
    • 함수형 포인터, functor, 람다식 모두 가능함
void freeFunc(int num){
   cout << num;
};

void runFunction(
   int num,
   const std::function<void(int)>& fn){
      //function 사용
      fn(i);
   }

int main(){
// 1. 함수 포인터 전달
   void (*fnPtr)(int) = freeFunc;
   runFunction(10, fnPtr);

// 2. 함수 객체 전달
   FunctionObj funcObj;
   runcFunction(10, funcObj);

// 3. 람다식 전달
   auto lambdaFn = [](int num){
      cout << num;
   };
   runFunction(10, lambdaFn);
}

참고

코드없는 프로그래밍(유투브)

반응형

'C++ > C++' 카테고리의 다른 글

[C++]병렬 프로그래밍  (0) 2021.03.11
[C++]스마트 포인터  (0) 2021.03.09
[C++]LR value 및 최적화  (0) 2021.03.09
[C++]빌드 프로세스  (0) 2021.03.09
[C++]메모리 구조  (0) 2021.03.09
반응형

1.async

  • 사용 예시
// async : 즉시 실행
auto a1 = std::async(std::launch::async, foo); // 이 때 스레드 실행
std::cout<<a1.get();

//deferred : 리턴값을 받아올 때 실행
auto a1 = std::async(std::launch::deferred, foo);
std::cout<<a1.get(); // 이 때 스레드 실행
  1. 정책

    • async : 새로운 스레드를 즉시 실행
    • deferred : 리턴값을 받아올 때 실행
  2. thread와의 차이점

    • 직접 스레드를 관리(생성, 삭제) 하지 않음
    • 함수에서 던진 예외에 대해 예외처리 가능
    • oversubscription
      • 스레드는 너무 많은 스레드 만들면 중단
      • 내부적으로 task관리해주기 때문에 중단 없음
    • 스레드를 직접 만들지 않고 스레드 풀 이용
    • 반환값을 받을 수 있다.
future<int> a1 = async(launch::async, foo);
const int ret = a1.get();

2.OpenMP

  1. 병렬 프로그래밍을 쉽게 할 수 있게 제공하는 API
  2. 사용 방법
    • 헤더 추가 : omp.h
    • 사용 : 부하가 많은 곳 위에 명령 입력
      #pragma omp parallel for
    • fork and join 모델로 컴파일 됨
    • 코어 개수 만큼 스레드 생성
#include <omp.h>
void main(){
   int a[1000];
   int b[1000];
   int c[1000];

   #pragma omp parallel for
   for(int i=0; i< 1000 ; i++){
      c[i] = a[i] + b[i];
   }
}
  1. 옵션
    • 위의 구문 뒤에 옵션 추가 가능

1)schedule(dynamic,1) 옵션

  • 1 = chuncksize, defualt = 1
  • chuncksize 개수만큼 배열을 태크스로 나누고, 코어 개수 만큼 스레드 런칭
  • dynamic하게 태스크를 수행하여, 먼저 끝난 스레드는 다음 태스크를 수행
  • static 옵션은 스레드가 수행할 태크스를 미리 정하고 끝나면 기다리므로 비효율적

참고

코드없는 프로그래밍(유투브)

3.CUDA

  1. 개발 순서
    • 커널(함수) 선언
    • 변수를 할당(cudaMalloc)
    • 변수를 복사(cudaMemcpy)
    • 동작 수행
    • 결과 변수를 복사(cudaMemcpy)
    • 변수 메모리 해제(cudaFree)
__global__
void add(int n, float *x, float *y, float *z){
   int i = blcokIdx.x * blockDim.x + threadIdx.x;
   if( i < n){
      z[i] = x[i] + y[i];
   }
}
void main(){
   int N = 100000;
   std::vector<float> x(N);
   std::vector<float> y(N);
   std::vector<float> z(N);

   float * d_x, *d_y, *d_z;
   cudaMalloc(&d_x, N*sizeof(float));
   cudaMalloc(&d_y, N*sizeof(float));
   cudaMalloc(&d_z, N*sizeof(float));

   cudaMemcpy(d_x, x.data(), N*sizeof(float), cudaMemcpyHostToDevice);
   cudaMemcpy(d_y, y.data(), N*sizeof(float), cudaMemcpyHostToDevice);

   add<<<(N+255)/256, 256>>>(N, d_x, d_y, d_z);

   cudaMemCpy(z.data(), d_z, N*sizeof*float), cudaMemcpyDeviceToHost);

   cudaFree(d_x);
   cudaFree(d_y);
   cudaFree(d_z);
}

4. thread에서 메모리 맵

  1. 로컬 변수(스택 공간)는 각 스레드에 종속적
  2. 힙과 static 공간은 공유함
    • race condition 발생 가능

5.false sharing

  1. 병렬 프로그래밍이 더 느릴 수 있다.
  2. 원인
    • 멀티 코어 환경에서 각 코어에서 접근하고 있는 데이터가 같은 캐시라인에 있을 때 발생
    • 실제 공유 데이터가 아님에도 하드웨어에서는 공유하는 것으로 착각
    • 동기화가 발생하여 속도가 저하됨
  3. 해결 방법

6. condition variable

  1. 한 스레드에서 다른 쓰레드로 신호를 보냄
  2. 신호를 받은 쓰레드는 컨디션 밸류를 체크하고 동작 수행
  3. 컨디션 밸류는 두 쓰레드에서 쓰기 때문에 뮤텍스 필수!
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex m;
std::condition_variable cv;
int condition = 0;

void foo(){
   std::unique_lock<std::mutex> lock(m);
   cv.wait(lock, []{return condition==1;})
//lock is acquired, mutual exc job
   lock.unlock();
   // do rest jobs;
}
int main(){
   std::thread waitngT(foo);
   {
      std::scoped_lock lock(m);
      condition = 1;
   }
   cv.notify_one();
   waitngT.join();
}

참고

코드없는 프로그래밍(유투브)

반응형

'C++ > C++' 카테고리의 다른 글

[C++] 함수형 프로그래밍  (0) 2021.03.11
[C++]스마트 포인터  (0) 2021.03.09
[C++]LR value 및 최적화  (0) 2021.03.09
[C++]빌드 프로세스  (0) 2021.03.09
[C++]메모리 구조  (0) 2021.03.09
반응형

1. 스마트 포인터란?

  1. 스택의 포인터 변수가 없어질 때 자동 메모리 해제
  2. 종류
    • unique_ptr
    • shared_ptr
    • weak_ptr

2.unique_ptr

  1. exclusive ownership
    • 한 오브젝트에 하나의 포인터만 허용함
  2. 생성 방법
unique_ptr<Cat> catPtr = make_unique<Cat>()
  1. get 함수 또는 연산자를 통해 자원 접근 가능
//operator -> 를 이용해 자원 접근
catPtr->doSomething();

// get함수를 통해 자원 접근
catPtr.get() //포인터를 반환
  1. std::move를 통해 소유권 이전 가능
    • 소유권을 이전한 unique_ptr을 댕글링 포인터(dangling pointer) 라고 함
unique_ptr<Cat> catPtr1 = move(CatPtr)
  1. unique_ptr을 함수 인자로 전달하기
    • unique_ptr은 복사를 수행하지 않기 때문에 함수 인자로 전달 불가
    • unique_ptr에서 관리하는 자원을 직접 전달
void do_something(Cat* ptr) { };
do_something(catPtr.get());
  1. unique_ptr을 원소로 가지는 컨테이너에서 사용 방법
std::vector<std::unique_ptr<A>> vec;
std::unique_ptr<A> pa(new A(1));

//1. 복사 생성자가 없기 때문에 오류 발생!
vec.push_back(pa);

//2. 소유권을 이전하면서 vector에 추가
vec.push_back(std::move(pa));

//3. emplace_back 사용 시 생성하면서 컨테이너에 넣을 수 있음
vec.emplace_back(new A(1));
  1. 주로 멤버 변수가 포인터일 경우 사용

3. shared_ptr

  1. Shared ownership
    • 한 오브젝트에 여러 포인터 가능함
  2. Reference count를 계산하여, 아무도 가리키지 않을 때 자동으로 메모리 해제
  3. 생성 방법
shared_ptr<Cat> catPtr = make_shared<Cat>()
  1. 자원을 할당 시 주의 사항
    • 자원을 먼저 할당하고 shared_ptr 생성자 인자로 주소값을 전달하지 않도록 하자!
A* a = new A();
// 2개의 shared_ptr 객체가 각각 따로 제어블록을 생성함
// 참조계수가 각각 1을 가짐
std::shared_ptr<A> pa1(a);
std::shared_ptr<A> pa2(a);
  1. 클래스에서 this를 사용해 shared_ptr을 만들 때
    • 클래스에서 enable_shared_from_this<A> 를 상속 받음
    • shared _from _this()를 통해 this를 shared_ptr로 만들자!
class A : public std::enable_shared_from_this<A>{
   std::shared_ptr<A> get_shared_ptr() {
      return shared_from_this();
   }
}
  1. 원형 참조가 있으면 여전히 메모리 릭 발생 가능
    • weak_ptr을 통해 해결 가능
class Cat{
public:
   std::shared_ptr<Cat> mFriend;
};

int main(){
   std::shared_ptr<Cat> pKitty = std::make_shared<Cat>();
   std::shared_ptr<Cat> pNabi = std::make_shared<Cat>();

   pKitty->mFriend = pNabi;
   pNabi->mFriend = pKitty;
}

4. weak_ptr

  1. 일반 포인터와 shared_ptr 사이에 위치한 스마트 포인터
  2. 참조하여도 reference count가 증가되지 않음
  3. weak_ptr 자체로는 원래 객체를 참조할 수 없음
    • weak _ptr 생성시 shared _ptr 또는 weak _ptr을 생성자 인자로 받음
    • 일반 포인터 주소값으로 weak_ptr 생성 불가
    • 가리키는 객체가 이미 소멸되었으면, 빈 shared_ptr로 변환
    • 아닐 경우 해당 객체를 가리키는 shared_ptr로 변환
  4. lock 함수를 통해 shared_ptr로 변환
std::weak_ptr<A> other(std::shared_ptr<A>(new A(1)));
std::shared_ptr<A> o = other.lock();

참고

반응형

'C++ > C++' 카테고리의 다른 글

[C++] 함수형 프로그래밍  (0) 2021.03.11
[C++]병렬 프로그래밍  (0) 2021.03.11
[C++]LR value 및 최적화  (0) 2021.03.09
[C++]빌드 프로세스  (0) 2021.03.09
[C++]메모리 구조  (0) 2021.03.09
반응형

1. 값, 포인터, 참조 전달

  1. 어셈블리 코드로 변경하면 포인터, 참조는 동일 형태
  2. 가급적 포인터가 필요한 경우 제외하고 참조 이용
    • const int& 형태로 사용가능하기 때문!
  3. 값으로 전달 시 크기가 커지면 불필요한 공간 사용
    • 참조 전달 사용

2. L value, R value

std::string a = "abc";
std::string b = std::move(a);
  1. a 는 L value
  2. "abc" 는 R value
    • 한 번 불려지고 다음에 사용 안함
  3. std::move(L value)
    • L value를 R value로 변경해줌
    • a가 가리키던 "abc"가 b로 이동하고 a는 빈값 저장됨
  4. 예시
// 값 전달 : 2번 복사
void storeByValue(string s){
    string b = s;
}

// L value 전달 : 1번 복사
void storeByLRef(string& s){
    string b = s;
}

// R value 전달 : 0번 복사
void storeByRRref(string &&s){
    string b = std::move(s);
}
  1. 값에 의한 전달
    • 2번 복사 일어남
  2. L value 전달
    • 1번 복사 일어남
  3. R value 전달
    • 복사 없음

3. 입력값 최적화

  1. 인자는 값에 의한 전달로 구현
  2. 내부에서 std::move로 작성
  3. 결과
    • L value로 넘어오면 1 copy 수행
    • R value로 넘어오면 0 copy 수행

4. RVO(Return Value Optimization)

  1. return by value로 적용
    • RVO 작동하여 0 copy 발생

참고

코드없는 프로그래밍(유투브)

반응형

'C++ > C++' 카테고리의 다른 글

[C++]병렬 프로그래밍  (0) 2021.03.11
[C++]스마트 포인터  (0) 2021.03.09
[C++]빌드 프로세스  (0) 2021.03.09
[C++]메모리 구조  (0) 2021.03.09
[C++]연산자 오버로딩  (0) 2021.03.09
반응형

1. extern vs static

  1. 링크의 방향을 결정(외부 또는 외부)
  2. extern int a
    • 다른 파일의 전역 변수 a를 사용함
  3. extern void func()
    • 함수는 기본값이 extern(생략되어 있음)
  4. static int a
    • 다른 파일에서 a를 찾을 수 없음
  5. static void bar()
    • 파일 내부에서만 호출 가능한 함수

2. gcc debug

  1. 컴파일
gcc main.cpp -g
  1. gdb 실행
gdb main.out
  1. 디버깅 시작

    • start 입력
  2. 다음 줄 실행

    • next 입력
  3. 뷰어 제공

    • ctrl + x + a
    • n : 다음 줄 이동
    • break 26 : 26번줄 브레이크 적용
    • break 함수이름 : 함수 첫 호출에 브레이크 적용
    • continue : 브레이크 포인터에서 멈춤
    • step : 함수 안으로 들어감
    • print 변수명: 변수 정보 출력
    • bt : 콜 스택을 보여줌

3. static library

  1. 오브젝트 파일들을 모아 하나의 파일로 생성한 것
  2. 이름은 lib이름.a 형태
  3. 링킹 시점에 실행파일에 바인딩 된다.

4. Dynamic library

  1. 이름은 lib이름.so 형태
  2. 빌드시 -fPIC 옵션 줘야함
    • 여러 프로그램에서 콜 될 수 있도록 생성시 주소를 상대주소로 설정
  3. loadtime에 바인딩 하는 방법
  4. runtime에 바인딩 하는 방법

참고

코드없는 프로그래밍(유투브)

반응형

'C++ > C++' 카테고리의 다른 글

[C++]스마트 포인터  (0) 2021.03.09
[C++]LR value 및 최적화  (0) 2021.03.09
[C++]메모리 구조  (0) 2021.03.09
[C++]연산자 오버로딩  (0) 2021.03.09
[C++]기초 내용 정리  (0) 2021.03.09
반응형

1. 메모리 구조

2. 데이터 영역

  1. 전역, static 변수가 저장됨(rw 영역)
  2. 초기화 되지 않으면 bss영역에 저장
  3. 프로그램이 종료되면 반환

3. 스택 영역

  1. 일반적인 변수가 저장되며 함수 블록 단위로 저장
  2. 하나의 블록은 인자, 일반변수, 리턴값으로 저장
  3. 함수가 종료되면 LIFO로 함수 블록이 반환
  4. 런타임 시간에 크기 변경 불가

4. 힙 영역

  1. 동적 메모리 영역
  2. 할당 후 해제가 반드시 필요함
  3. 읽고 쓰는 속도가 스택에 비해 약간 느림

5. 메모리 관리 방법

  1. 일반 적인 경우 스마트 포인터를 사용

    • delete를 해주지 않아도 자동으로 메모리 해제됨
  2. 배열 형태 사용 필요시 vector를 사용

6. 메모리 누수 찾는 방법(팁)

  1. valgrind 프로그램명

7. 언제 스택? 힙?

  1. 데이터량이 mb 이하이면 스택(array 사용)
std::array<int, 1000> ar;
  1. 데이터량이 mb 이상이면 힙(vector 사용)
std::vector<cat, 1000000> ve;
  1. 왜?
    • 스택은 위에서부터 그냥 쌓기 때문에 힙보다 빠름

참고

코드없는 프로그래밍(유투브)

반응형

'C++ > C++' 카테고리의 다른 글

[C++]스마트 포인터  (0) 2021.03.09
[C++]LR value 및 최적화  (0) 2021.03.09
[C++]빌드 프로세스  (0) 2021.03.09
[C++]연산자 오버로딩  (0) 2021.03.09
[C++]기초 내용 정리  (0) 2021.03.09
반응형

1. 연산자 오버로딩

  1. 연산자 오버로딩시 const를 사용하라!
  2. 연산자 오버로딩 방법 두 가지

1)멤버 함수 오버로딩

  • 구현 : 멤버 함수로 연산자를 오버로딩
Point operator+(const Point& ref);
// 사용시 해석
pos.operator+(pos2);

2)전역 함수 오버로딩

  • 구현 : 전역 함수로 구현하고 클래스 내에서 friend 정의
  • 멤버 변수 접근 안되므로 getter 또는 friend 필요!
// 클래스 내부에서 정의
friend Point operator+(Point&, Point&);
// 클래스 밖에서 전역 함수 구현
Point operator+(Point& pos1, Point& pos2){}
// 사용시 해석
operator+(pos1, pos2);
  1. 무조건 전역 함수 오버로딩을 사용하는 경우

    • 이항 연산의 왼쪽항이 오버로딩 객체가 아닐 때 사용

    • Point 객체에 상수 3을 곱할 경우

Point operator*(int, Point&);

//사용
Point pos2 = pos * 3;
  1. 객체를 cout 가능하게 하기
    • ostream을 전역 함수 오버로딩 사용
ostream& operator<<(ostream& os, Point& pos){
    os <<'('<< x << ',' << y << ')' << endl;
    return os;
}
  1. 연산자 오버로딩 시 주의 사항
    • Animal 클래스(부모) 에서 연산자 오버로딩
    • Cat 클래스(자식)에서 연산자 오버로딩 안함
    • 위의 상태에서 연산자 오버로딩 사용시 문제 발생 가능
if (Cat1 == Cat2)
// 서로 다른 객체 이지만 부모가 동일하여 True발생 가능함
// Cat에도 연산자 오버로딩을 작성해야 함!

2. 단항 연산자 오버로딩(++)

  1. 전위 증가
const Point& operator++(){
    m_nX++;
    m_nY++;
    return *this;
}
++pos1;
  1. 후위 증가
const Point operator++(int){
    const Point refPos(m_nX, m_nY);
    m_nX += 1;
    m_nY += 2;
    return refPos;
}
pos1++;

3. 대입 연산자 오버로딩

  1. 이미 생성 및 초기화 되었으면 = 기호 사용시 대입 연산자 호출됨
  2. 대입 연산자 미구현 시 Defualt 대입 연산자 생성 및 호출
    • 얕은 복사 진행
  3. 상속 시 부모 클래스의 대입연산자를 명시적으로 호출 필요
First::operator=(ref);

4. new, delete 오버로딩

  1. new 연산자 오버로딩
    • new 연산자의 수행 범위 3가지
      • 메모리 할당
      • 생성자 호출
      • 할당 자료형 변환
    • 위 중 메모리 할당 역할만 오버로딩 가능
  2. new, delete 오버로딩 함수는 static 함수
    • 일반 함수로 선언해도 static 함수로 간주
    • 객체 생성 전 호출되어야되는 함수이기 때문
  3. 구현 방법
//new
void* operator new(size_t size) {...}
void* operator new[](size_t size()) {
    void* adr = new char[size];
    return adr;
}

//delete
void operator delete(void* adr)
void operator delete[](void* adr){
    delete[] adr;
}

5. 포인터 연산자 오버로딩

  1. 포인터 연산자 오버로딩
Number& operator*(){
    return *this;
  1. 지시 연산자 오버로딩
Number* operator->(){
    return this;
}

6. 함수 호출 연산자 오버로딩

struct FuncObj{
   int Add()(int a, int b) const{
      return a + b;
   }
}

int main(){
   FuncObj add;
   std::cout<<add(10,20);
}

7. 배열 인덱스 연산자 오버로딩

  1. 값 조회용 오버로딩
int operator[](int idx) const{
   return arr[idx];
}
  1. 값 입력용 오버로딩
int& operator[](int idx) {
   return add[idx];
}

8. 일반 변수 오버로딩

operator int(){
   return x;
}

int main(){
   Point pos(3,2);
   int a = pos; // a는 3을 가짐
}
반응형

'C++ > C++' 카테고리의 다른 글

[C++]스마트 포인터  (0) 2021.03.09
[C++]LR value 및 최적화  (0) 2021.03.09
[C++]빌드 프로세스  (0) 2021.03.09
[C++]메모리 구조  (0) 2021.03.09
[C++]기초 내용 정리  (0) 2021.03.09
반응형

1. 헤더 가드

  1. 필요성
    • 헤더가 중복으로 로딩되면 오류가 발생할 수 있음
    • 이미 헤더가 로딩되었을 경우는 로딩하지 않도록 정의
  2. 사용방법
    • C style
#ifndef TEST
    #def TEST
    //헤더 내용
#endif
  • C++ style
#progma once
    //헤더 내용

2.구조체와 클래스 유일한 차이

  1. 별도의 접근제어 지시자를 입력하지 않으면
    • 구조체 : public이 default
    • 클래스 : private이 default

3. inline 함수

  1. 매크로 함수 특징(#define)
    • 일반 함수보다 실행속도가 빠르다.
    • 복잡한 함수를 정의하기 어렵다.
    • 전처리기에 의해 처리된다.
    • 자료형에 의존적이지 않은 함수 가능
    • 사용 방법
#define SQUARE(x) ((x)*(X))
  1. inline 함수 특징
    • 컴파일러에 의해 처리된다.
    • 템플릿을 이용해 자료형에 의존적이지 않은 함수 가능
    • 사용 방법
inline int SQUARE(int x){
    return x*x;
}

4. 객체간의 대화방법(Message Passing)

  1. 한 객체가 다른 각체에게 메시지 전달 방법

    ex) seller 아저씨 사과 2000원 어치 주세요.

void Buyer::BuyApples(Seller &sel, int mon)

5. const

  1. const 함수
    • 함수 내에서 멤버 변수를 변경 안함
    • 함수 내에서 const가 아닌 함수 호출 제한
int GetY() const;
  1. const 객체
    • 객체는 const 멤버 함수만 호출 가능
const Simple sim(20)
  1. mutable 키워드

    • const 함수에서 예외적으로 값 변경 허용
mutable int num;

6. 멤버 이니셜라이저

Point pos;
string name;
car::car(int x, int y, string s)
    : pos(x,y), name(s) {}
  1. 객체 pos에 x,y를 전달받는 생성자 호출
  2. 일반적인 변수(name)도 이니셜라이저로 초기화 가능
  3. 선언과 동시에 초기화 해주는 형태로 바이너리 코드가 생성됨
  4. const 변수도 초기화 가능함
  5. 참조자도 초기화 가능함
Position& pos
Car(Position &pos1) : pos(pos1) {}

7. 생성자

  1. 생성자를 생략해도 무조건 생성자 호출됨
    • Default 생성자가 자동 생성 후 호출됨
  2. malloc으로 객체 생성 시 생성자 호출 안됨
  3. new로 객체 생성 시 생성자 호출됨
  4. 생성자가 있으면 Default 생성자 자동 생성 안됨

8. Self reference

  1. this 포인터를 이용해 자기자신을 반환 가능
SelfRef& Add(int a){
    this->num+=a;
    return *this;
}
  • ref.Add(1).Add(1)과 같이 사용 가능

9. 복사 생성자

  1. 복사 생성자 미정의시 Default 복사 생성자 생성
Simple(const Simple& copy)
  1. 복사생성자 인자에는 반드시 &가 있어야함
  2. explicit 키워드
    • 아래와 같은 묵시적 변환이 안 일어나게 하는 것
    • 묵시적 변환이 많으면 코드 예측 어려움
Simple sim2 = sim1
// Simple sim2(sim1)
// => 위와 같은 형태로 묵시적 변환 일어남
// => explicit 키워드 붙혀줌
explicit Simple(const Simple &copy)
  1. 얕은 복사
    • 포인터 변수 복사 시 원래 변수의 주소만 복사함
    • 원래 변수가 변경되면 같이 변경됨
    • Default 복사 생성자는 얕은 복사 수행
  2. 깊은 복사
    • 포인터 변수 복사 시 메모리를 재할당 받도록 복사 생성자를 별도로 정의
  3. 복사 생성자의 호출 시점(3가지)

1)기존 객체를 이용해 새로운 객체를 초기화

Simple sim = sim2

2)call by value 방식으로 객체를 인자로 전달

void func(Simple sim)

3)참조형이 아닌 객체 반환

  • func에서 return 될 때 임시 객체 생성
  • 받는 ref가 없으면 임시 객체 즉시 소멸
  • 받는 ref가 있으면 받는 ref가 소멸될 때 소멸
  • ref는 임시객체에 이름만 부여(재복사 안함)
Simple func(Simple ref) {
    return ret;
}

Simple ref = func(obj);

10. friend

  1. A클래스에서 B클래스를 friend 선언 시
    • B클래스에서 A클래스의 private 멤버 접근 가능
    • friend 선언 시에 클래스 원형 선언도 포함함
class B; // friend 선언시 원형을 포함하므로 이구문 필요 없음

// A클래스 에서 아래 입력...
friend class B;
  1. A클래스에서 friend 함수 선언 시
    • 함수에서 private 멤버 접근 가능
// A클래스에서 아래 입력...
friend void showPtn(const Point& pnt)

void showPtn(const Point& pnt){
    // A클래스 멤버 접근 가능
}
  1. friend는 가급적 사용을 지양
    • 꼭 필요한 경우에만 사용

11. static

  1. static 멤버 변수(클래스 변수)
    • 클래스 당 하나씩만 생성됨
    • public으로 선언시 클래스명::변수명 사용 가능
    • 클래스 밖에서 초기화 필요
// Simple 클래스
static int cnt;

// 클래스 외부에서 초기화 필요
int Simple::cnt = 0;
  1. static 멤버 함수

    • 함수 내부에서 static 멤버 변수와 static 멤버 함수만 호출 가능
    • 일반 멤버 변수 접근 불가
    • 클래스명::함수명() 형태로 사용 가능
  2. const static 멤버

    • 선언과 동시에 초기화 가능
const static int KOR = 100;

12. 상속

  1. 자식 클래스 생성자에서 부모 클래스 생성자를 명시하지 않으면 부모 클래스의 void 생성자 호출
  2. protected 상속
    • public 멤버는 protected로 변경하여 상속
  3. public 상속
    • 별도 변경 없음
  4. private 상속
    • 모든 멤버를 private로 변경하여 상속
  5. 상속의 조건
    • is a 관계(노트북 is a 컴퓨터)가 성립해야함
  6. has a 관계도 상속 가능하지만 일반적으로 다른 기술들 사용

13. 상속과 다형성

  1. 부모 클래스 포인터 변수는 모든 자식 객체를 가리킬 수 있다
base* ptr = new derived();
  1. 그러나 함수 호출은 포인터형에 해당하는 멤버만 호출 가능
ptr->derivedFunc() // (X)
  1. virtual 함수 사용시 포인터 변수가 실제 가리키는 객체를 참조하여 호출 대상 결정
virtual void myFunc();

Person* ptr = new Student();
ptr->myFunc(); // => Student의 myFunc 호출됨
  1. 순수 가상 함수
    • 함수의 몸체를 정의하지 않음을 컴파일러에 알림
    • 순수 가상함수를 지닌 클래스는 객체 생성 불가
virtual int getPay() = 0;
  1. 가상 소멸자
// 1. 일반 소멸자 정의
~Person();

Person* ptr = new Student();
delete ptr; // => Person의 소멸자만 호출됨

// 2. 가상 소멸자 정의
virtual ~Person();

Person* ptr = new Student();
delete ptr; // => Student 소멸자도 호출됨

14. 가상의 원리와 다중 상속(effective 7 참고)

  1. virtual 함수 생성하면 컴파일 시 포인터 주소 추가

    • 64비트 기준 객체의 크기가 8바이트 증가
    • 포인터는 virtual 테이블을 가리킴
  2. virtual 테이블이 각 함수를 가리킴

    • Animal VT는 Animal의 speak()
    • cat VT는 Cat의 speak()
  3. 함수 호출 시 가상 함수 테이블에서 찾아서 호출

  4. 가상 상속

    • 다중 상속에서 두 개의 부모가 같은 Base를 가지고 있을 때 Base를 한번만 상속하는 방법
class MidOne : virtual public Base{...}
class MidTwo : virtual public Base{...}
class Last : public MidOne, public MidTwo{...}
  1. 일반 상속 시(Lion이 Animal을)
    • VT 포인터 하나 가짐
    • 포인터 시작지점은 Animal
    • Animal이 끝나면 Lion 정보가 메모리에 존재
  2. virtual 상속시
    • lion 클래스 포인터 시작이 lion
    • animal, lion의 VT 포인터 모두 가짐
    • Animal 포인터로 lion 가리키면 Lion VT의 offset 정보를 가지고 있음(16바이트 전에 Lion의 시작점이 있다.)
    • thunk 함수를 통해 Lion::speak 함수 호출 가능
    • thunk 함수는 offset을 계산한 Lion::speak 함수를 가리킴
    • Lion 포인터로 Lion 가리키면 그냥 호출 가능

15. 템플릿

  1. 함수 템플릿 사용 방법
// 1. 생성
template<typename T>
T Add(T num1, T num2) {}

// 2. 사용
Add<int>(3,4); // int형
Add<int>(3,5,4.5); // double형
  1. typename 대신 class 사용 가능
template<class T>
  1. 컴파일 때 입력된 자료형에 맞게 함수가 생성됨

    • 최초 1회 생성, 이후는 생성된 함수 사용
    • 컴파일 속도가 약간 느려짐
  2. 용어 정리

    • 함수 템플릿 : 함수를 만드는 템플릿 정의
    • 템플릿 함수 : 템플릿에 의해 생성된 함수
  3. 일반 함수가 정의되어 있으면, 템플릿 함수보다 우선 호출됨

  4. 템플릿 타입 여러 개 적용 가능

template<class T1, class T2>
void ShowData(T1 num1, T2 num2)

// 사용
ShowData<int, double>(65, 3.6) // int, double형
}
  1. 함수 템플릿의 특수화
    • 특정 인자로 들어오면 명시적으로 특정 함수를 사용하게 정의 하는 것
    • ex) Max함수에서 문자가 들어오면 길이 비교
template<>
char* Max<char*>(char* a, char* b){
    return strlen(a) > strlen(b) ? a : b;
}
  1. 클래스 템플릿
//1. 선언
template<typename T>
class Point {
    T xpos, ypos;
public:
    Point(T x, T y)
    : xpos(x), ypos(y) {}
};

// 사용
Point<int> pos(1,2); //int형 Point 객체
Point<double> pos(1.1, 3.1) // double형
  1. 선언부와 구현부 파일 분리시 주의 사항

    • 템플릿 사용 함수 위에 template 입력 필수!
    • 사용하는 파일에서 템플릿 cpp 파일도 include 필요
    • 일반적으로 헤더파일안에 구현부도 포함
  2. 클래스 템플릿 특수화

    • 특수 자료형을 기반으로 생성된 객체에 대해 구분되는 다른 행동 양식 적용!
template<>
class SoSimple<int>{
    public:
    int Simplefunc(int num){...}
}
  1. 템플릿 인자 및 기본값 설정
template<typename T = int, len = 7>
class SimpleArray{
    T arr[len];
}

16. 예외 처리

  1. try
    • 예외를 발견 한다.
  2. catch
    • try블록에서 발생한 예외를 처리하는 로직
  3. throw
    • 예외가 발생 했음을 알림
  4. 예제
try {
    if(num2 == 0)
        throw num2;
} catch(int expn) {
    cout << expn <<"은 못옴!";
}
  1. 함수에서 예외 처리가 되지 않았을 때
    • 함수를 콜한 영역으로 예외처리에 대한 책임과 데이터 전달됨
    • 함수에 대한 예외 발생 시 함수 호출한 곳에서 예외 처리 가능
// 예외를 던지는 함수
void Divide(int num1, int num2){
    if(num2 == 0)
        trhow num2;
}

// 함수를 콜하는 부분
// Divide 함수 수행 하다 예외 발생시
// 아래 catch 부분에서 예외 처리 가능
try{
    Divide(num1, num2);
} catch(int expn){ ... }
  1. 함수 선언시 throw 키워드 추가
    • 예외 발생이 있다면 throw 키워드를 꼭 붙여야함!
int Func(int num) throw(int, char)
// int와 char 형식의 예외 발생이 가능하다!
// 이 함수 사용시 try catch문이 필요하다고 알림
  1. 클래스 형태로 예외 정의 가능
    • 예외 클래스를 정의
    • 예외 클래스는 exception 클래스를 상속!
void deposit(money) {
    if ( money < 0 ) {
        //expn 예외 객체 생성 및 throw 발생
        DepositException expn(money) ;
        throw expn;
    }
}
try {
    deposit(-200) ;
} catch ( DepositException &expn) {
    expn.showError();
}

17. C++ 형변환 연산자

  1. dynamic_cast(expr)
    • 상속 관계에서 안전한 형 변환 가능
    • T에 객체는 포인터 또는 참조형 가능
    • 실행시간에 형변환 되므로 속도 느림
  2. static_cast(expr)
    • C스타일의 형변환 연산자 대신 사용
    • 컴파일 시간에 형변환 되므로 속도 빠름
    • 설계 잘되어 있다면 dynamic 대신 static 사용
  3. const_cast(expr)
    • 참조자의 const 성향을 제거하는 형변환
    • 주로 인자 전달시 불일치 제거를 위해 사용
  4. reinterpret_cast(expr)
    • 전혀 상관이 없는 형 변환에 사용

18. 함수 포인터

  1. 정적 함수 호출
    • 일반 함수나 static 멤버 함수를 가리키는 포인터
    • 선언
// 선언
void (*pFunc)(int);
// 반환값이 void이고 인자가 int형 하나인 함수를 가리킬 수 있는 함수 포인터
  1. 멤버 함수 호출
    • 선언
void(Point::*pFunc)();
// 반환값이 void이고 인자가 없는 Point 멤버 함수를 가리킬 수 있는 함수 포인터 선언

//사용
Point pt;
(pt.*pFunc)(); // 객체로 사용
Point *p;
(p->*pFunc)(); // 주소로 사용

19. 함수 객체

  1. 장점
    • 객체 이므로 멤버 변수, 멤버 함수를 가질 수 있음
    • 속도가 일반 함수보다 빠름
    • 인라인화 될 수 있음(함수 포인터는 안됨)
    • 컴파일러가 쉽게 최적화 가능
//선언
struct Adder{
   int operator()(int a, int b){
      return a_b;
   }
};


int main(){
// 사용1
   Adder add;
   add(3,2);

// 사용2 : 인자로 전달
   for_each(arr, arr+5, Adder());
}

20. C++ 팁

  1. 클래스의 크기는 가장 큰 멤버 변수의 배수로 끝남
    • double이 있으면 8의 배수로 끝남
  2. 각 변수는 자기 크기의 배수에서 시작함
    • double는 8의 배수에에서 시작함
    • 만약 int, double순으로 멤버 변수 선언시
    • 4(int), 4(padding), 8(double)로 저장됨
  3. 클래스에 로우 포인터가 멤버 변수로 있으면
    • 파괴자, 복사/이동 생성자, 복사/이동 대입 구현 필요
  4. 클래스에 로우 포인터 없다면
    • defualt 복사/이동 생성자/대입연산자 사용
  5. 생성자가 private에 있는 것과 =delete는 동일
  6. 생성자 인자가 1개이면 앞에 explicit 명시
    • 원하지 않는 형변환을 방지
    • 링크 참고
Point pt;
pt = 10 //(x)
pt = Point(10) // (O)
  1. iotream 상속 구조
    • 여기서 basic iostream이 자주쓰는 iostream
    • print 함수 구현시 ostream&을 인자로 사용하면, 상속 구조에 따라 ostreamstream, ofstream도 사용 가능
//사용 1. cout
    print(cout) => 화면에 결과 출력
//사용 2. fstream
    ofstream ofs{"test.txt"};
    print(ofs) => 파일에 결과 쓰기
//사용 3. stringstream
    stringstream ss;
    print(ss) => string에 쓰기
반응형

'C++ > C++' 카테고리의 다른 글

[C++]스마트 포인터  (0) 2021.03.09
[C++]LR value 및 최적화  (0) 2021.03.09
[C++]빌드 프로세스  (0) 2021.03.09
[C++]메모리 구조  (0) 2021.03.09
[C++]연산자 오버로딩  (0) 2021.03.09

+ Recent posts

반응형