// 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(); // 이 때 스레드 실행
정책
async : 새로운 스레드를 즉시 실행
deferred : 리턴값을 받아올 때 실행
thread와의 차이점
직접 스레드를 관리(생성, 삭제) 하지 않음
함수에서 던진 예외에 대해 예외처리 가능
oversubscription
스레드는 너무 많은 스레드 만들면 중단
내부적으로 task관리해주기 때문에 중단 없음
스레드를 직접 만들지 않고 스레드 풀 이용
반환값을 받을 수 있다.
future<int> a1 = async(launch::async, foo);
const int ret = a1.get();
2.OpenMP
병렬 프로그래밍을 쉽게 할 수 있게 제공하는 API
사용 방법
헤더 추가 : 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];
}
}
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));
주로 멤버 변수가 포인터일 경우 사용
3. shared_ptr
Shared ownership
한 오브젝트에 여러 포인터 가능함
Reference count를 계산하여, 아무도 가리키지 않을 때 자동으로 메모리 해제
생성 방법
shared_ptr<Cat> catPtr = make_shared<Cat>()
자원을 할당 시 주의 사항
자원을 먼저 할당하고 shared_ptr 생성자 인자로 주소값을 전달하지 않도록 하자!
A* a = new A();
// 2개의 shared_ptr 객체가 각각 따로 제어블록을 생성함
// 참조계수가 각각 1을 가짐
std::shared_ptr<A> pa1(a);
std::shared_ptr<A> pa2(a);
클래스에서 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();
}
}
std::string a = "abc";
std::string b = std::move(a);
a 는 L value
"abc" 는 R value
한 번 불려지고 다음에 사용 안함
std::move(L value)
L value를 R value로 변경해줌
a가 가리키던 "abc"가 b로 이동하고 a는 빈값 저장됨
예시
// 값 전달 : 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);
}
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);
무조건 전역 함수 오버로딩을 사용하는 경우
이항 연산의 왼쪽항이 오버로딩 객체가 아닐 때 사용
Point 객체에 상수 3을 곱할 경우
Point operator*(int, Point&);
//사용
Point pos2 = pos * 3;
객체를 cout 가능하게 하기
ostream을 전역 함수 오버로딩 사용
ostream& operator<<(ostream& os, Point& pos){
os <<'('<< x << ',' << y << ')' << endl;
return os;
}
연산자 오버로딩 시 주의 사항
Animal 클래스(부모) 에서 연산자 오버로딩
Cat 클래스(자식)에서 연산자 오버로딩 안함
위의 상태에서 연산자 오버로딩 사용시 문제 발생 가능
if (Cat1 == Cat2)
// 서로 다른 객체 이지만 부모가 동일하여 True발생 가능함
// Cat에도 연산자 오버로딩을 작성해야 함!
// 예외를 던지는 함수
void Divide(int num1, int num2){
if(num2 == 0)
trhow num2;
}
// 함수를 콜하는 부분
// Divide 함수 수행 하다 예외 발생시
// 아래 catch 부분에서 예외 처리 가능
try{
Divide(num1, num2);
} catch(int expn){ ... }
함수 선언시 throw 키워드 추가
예외 발생이 있다면 throw 키워드를 꼭 붙여야함!
int Func(int num) throw(int, char)
// int와 char 형식의 예외 발생이 가능하다!
// 이 함수 사용시 try catch문이 필요하다고 알림
클래스 형태로 예외 정의 가능
예외 클래스를 정의
예외 클래스는 exception 클래스를 상속!
void deposit(money) {
if ( money < 0 ) {
//expn 예외 객체 생성 및 throw 발생
DepositException expn(money) ;
throw expn;
}
}
try {
deposit(-200) ;
} catch ( DepositException &expn) {
expn.showError();
}
17. C++ 형변환 연산자
dynamic_cast(expr)
상속 관계에서 안전한 형 변환 가능
T에 객체는 포인터 또는 참조형 가능
실행시간에 형변환 되므로 속도 느림
static_cast(expr)
C스타일의 형변환 연산자 대신 사용
컴파일 시간에 형변환 되므로 속도 빠름
설계 잘되어 있다면 dynamic 대신 static 사용
const_cast(expr)
참조자의 const 성향을 제거하는 형변환
주로 인자 전달시 불일치 제거를 위해 사용
reinterpret_cast(expr)
전혀 상관이 없는 형 변환에 사용
18. 함수 포인터
정적 함수 호출
일반 함수나 static 멤버 함수를 가리키는 포인터
선언
// 선언
void (*pFunc)(int);
// 반환값이 void이고 인자가 int형 하나인 함수를 가리킬 수 있는 함수 포인터
멤버 함수 호출
선언
void(Point::*pFunc)();
// 반환값이 void이고 인자가 없는 Point 멤버 함수를 가리킬 수 있는 함수 포인터 선언
//사용
Point pt;
(pt.*pFunc)(); // 객체로 사용
Point *p;
(p->*pFunc)(); // 주소로 사용
19. 함수 객체
장점
객체 이므로 멤버 변수, 멤버 함수를 가질 수 있음
속도가 일반 함수보다 빠름
인라인화 될 수 있음(함수 포인터는 안됨)
컴파일러가 쉽게 최적화 가능
//선언
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());
}
print 함수 구현시 ostream&을 인자로 사용하면, 상속 구조에 따라 ostreamstream, ofstream도 사용 가능
//사용 1. cout
print(cout) => 화면에 결과 출력
//사용 2. fstream
ofstream ofs{"test.txt"};
print(ofs) => 파일에 결과 쓰기
//사용 3. stringstream
stringstream ss;
print(ss) => string에 쓰기