2019년 5월 13일 월요일

C++ Reference

C++ reference에 대해서 잘못 알고있는 부분과 자세히 몰랐던 부분이 있어서
이 부분에 대해 공부한 후 포스팅을 해보려고 한다.





- Reference

C++에서는 Reference(&)라는 변수타입이 제공된다.
간단히 말해서 별명을 붙혀주는 기능이다.


int &ret = dp[curr];
cs
알고리즘 포스팅중 dp - top down으로 구현한 코드에 대부분 등장하는 코드이다.


ret = 30;
printf("dp[curr] : %d\n",dp[curr]);         // 30
cs
dp[curr]ret이라는 별명을 붙혀주었고 이 값을 30으로 변경했기 때문에  30으로 출력이 된다.





- Reference type

이러한 Reference는 세 가지 종류의 참조형을 제공한다.

  •  non-const value
  •  const value
  •  r-value (using &&)

int a = 10;
int& ref1 = a;            // okay [non-const l-value]
const int b = 20;
int& ref2_1 = b;        // not okay
const int& ref2_2 = b;    // okay [const l-value]
int&& ref3 = 30;        // okay [r-value]
cs

l-value, r-value에 대해서는 다음 포스팅에서 다뤄보도록 하겠다.





- Pass by reference

reference를 함수 인자부분에 사용하는 것을 말한다.
인자 변수가 복사되어 생성되지 않기 때문에 Pass by value에 비해 속도가 빠르다.




int Square(const int& input) {
    int ret = input * input;
    return ret;
}
cs
const 키워드를 붙여서 함수 내부에 변경이 없도록 사용하는 경우가 많다.





- Return by Reference

이 부분은 조심해서 사용해야 한다.
reference를 함수 반환값으로 사용하는 것을 말한다.
이 기능을 수행할 때는 reference의 원본이 메모리 상에 유지되어야 한다. 
(당연한 말이지만 무심코 이 원칙을 지키지 않을 수 있다.)


#include <bits/stdc++.h>
using namespace std;
int& function() {
    int val = 10
    return val;
}
int& function2() {
    int val2 = 20;
    return val2;
}
int main(){
    int& ref = function(); 
    int& ref2 = function2();
    cout << ref << endl;        // output : 20
}
cs
위의 예시에서는 10이 출력될것 처럼 보이지만 20이 출력이된다.



처음 function()이 호출 되면 다음과 같은 주소에 값이 들어갈 것이다.



 그 다음 function() 함수가 종료되면 val변수는 사라졌지만 여전히 같은 주소를 지니게 된다.



 function2() 함수가 호출되면 ref, ref2변수 모두 val2의 주소값을 가지게된다.



결국 마지막에는 이런 결과를 얻게된다.



위의 과정은 심각한 오류를 초래할 수 있으므로 사용하지 말도록 하자.

아니면 static 변수로 선언하여 이 문제를 해결할 수 있다.

static 변수는 global 변수와 같이 data영역에 할당이 되고 
함수, 함수의 지역변수는 heap영역에 메모리 할당과 해제가 이루어 진다.



static 변수는 선언과 동시에 data영역에 존재해 함수 호출 후에도 남아있게 되기때문에 
위의 문제를 해결할 수 있다.


#include <bits/stdc++.h>
using namespace std;
int& function() {
    static int val = 10
    return val;
}
int& function2() {
    static int val2 = 20;
    return val2;
}
int main(){
    int& ref = function(); 
    int& ref2 = function2();
    cout << ref << endl;        // output : 10
}
cs




[출처]
https://boycoding.tistory.com/207 /
https://snbosoft.tistory.com/entry/%EC%A0%9C2%EC%9E%A5-C-%EA%B8%B0%EB%B3%B8-Reference%EB%A5%BC-return%ED%95%98%EB%8A%94-%ED%95%A8%EC%88%98%EC%9D%98-%EC%A0%95%EC%9D%98 /
https://www.tutorialspoint.com/cplusplus/returning_values_by_reference.htm /

2019년 2월 6일 수요일

C++ 디자인패턴 (Singleton pattern)

Singleton Pattern
생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 유일하게끔 사용하는 디자인 패턴

#include <iostream>
#include <string>
using namespace std;
class Singleton {
public:
    static Singleton* New(string name) {
        static Singleton *instance = nullptr;
        if (instance == nullptr) instance = new Singleton(name);
        return instance;
    }
    void print() {
        cout << "my name is " << _name << "\n";
    }
 
private:
    string _name = "";
    Singleton() {}
    Singleton(string name) :_name(name) {}
};
 
int main() {
    Singleton *instance = Singleton::New("jihoon");
    Singleton *instance2 = Singleton::New("taehoon");
    
    instance->print();
    instance2->print();
    return 0;
}
cs

2018년 11월 9일 금요일

C++ 디자인패턴 (Composite Pattern)

Composite Pattern
클라이언트에서 단일 객체와 복합 객체 모두 동일하게 다루기 위해 사용하는 디자인 패턴
#include <bits/stdc++.h>
using namespace std;
class Component {
public:
    Component() {}
    virtual ~Component() {}
    virtual void print(int= 0;
};
class Directory : public Component{
public:
    ~Directory() {}
    Directory() {}
    Directory(string id) :m_id(id) {}
    void add(Component *input) {
        m_comp.push_back(input);
    }
    void print(int tap = 0) {
        for (int i = 0; i < tap; i++printf("\t");    // tap
        printf("directory : %s\n", m_id.c_str());
        
        for (auto dir : m_comp) {
            dir->print(tap + 1);
        }
    }
 
private:
    vector<Component*> m_comp;
    string m_id;
};
class File :public Component {
public:
    ~File() {}
    File() {}
    File(string id) :m_id(id) {}
    void print(int tap = 0) {
        for (int i = 0; i < tap; i++printf("\t");    // tap
        printf("file : %s\n", m_id.c_str());
    }
private:
    string m_id;
};
int main() {
    Directory *dir_engineering = new Directory("Engineering");
    Directory *dir_computer_science = new Directory("Computer Science");
    Directory *dir_algorithm = new Directory("Algorithm");
    Directory *dir_AI = new Directory("AI");
 
    dir_algorithm->add(new File("Binary Search"));
    dir_algorithm->add(new File("BFS"));
    dir_algorithm->add(new File("Dinic Algorithm"));
    dir_computer_science->add(dir_algorithm);
 
    dir_AI->add(new File("Reinforcement Learning"));
    dir_AI->add(new File("CNN"));
    dir_computer_science->add(dir_AI);
 
    dir_engineering->add(dir_computer_science);
    dir_engineering->print();
    return 0;
}
cs

[출력값]

composite 패턴은 파일 시스템을 예시로 들면 이해하기 쉽다.
directory는 file을 담는것 뿐만 아니라 directory 또한 담을 수 있는데 다형성을 이용해 관리해준다.