반응형

주의_1 while문 안에 switch를 사용할 때 

while문안에 if 문에서 break 하면 그뒤에 코드들은 거치지 않는다, 즉 if문은 원하는 지점에서 while문을 탈출 시킬 수 있다

위와 같이 while 안에 if 문을 써서 조건을 만족하면 break 문을 사용하여 while 문을 탈출 시킬수 있다

 

그런데 조건문중에 switch 문이 존재하고, while문과 switch 문을 아래와 같이 사용하면

while 안에 switch 안에 break 는 while 문을 탈출 시키지 못한다

break 문이 있다 치더라도, while문을 빠져나오지 못한다, 이유는 switch 안에 break문의 용도는

다음 케이스 문을 거치지 않고, switch문을 중단 시키는 용도 뿐이지, while문을 빠져나오진 못한다

 

해결책

빠져나오게 하고 싶다면, switch 문을 가장 마지막에 두고, switch 문의 case 만족할때

while문의 조건을 두고 있는 bool 변수를 false 시키는 것이다, 그러나, while 문안에 if, break 처럼

원하는 부분에서 중단 시킬 없다

 

switch를 가장 마지막에 두고 while 조건을 false로 바꾸면 가능하긴 하다 그러나 if 문처럼 원하는 지점에서 바로 탈출할 수 없다.

 

 

 

또는 return 문을 써서 switch 문도 while 문을 원하는 지점에서 바로 탈출 할 수 있기는 하지만 그와 동시에 전체 함수가 종료 된다.

 

반응형
반응형

EX02 HEAP CORRUPTION DETECTED

동적 할당을 하는 프로그램을 만들던 도중, free() 함수를 실행할때 에러 발생

 

원인:

Google 찾아보니, 할당한 영역을 벗어나서 접근하게 될경우 발생하는 에러 라고

 

 

 

 

/*Decoding        */

FileStreamInit(&fileStream, fileName, "r"); //파일크기에 따른 g_CodeSize 초기화

 

if (g_CodeSize == 0)

{

     printf("\nError, No data in codefile, zero codeSize\n");

     exit(1);

}

 

g_Buffer = (char*)calloc(g_CodeSize, sizeof(char));

fread_s(g_Buffer, g_CodeSize, sizeof(char), g_CodeSize, fileStream);

decode(g_Buffer, g_CodeSize);

 

아래 decode 함수에서  str[i] != '\0' 원인 이었음

i size 만큼만 i++ 해야 되는데, 범위를 넘어서 버린듯

 

 

 

해결:

void decode(char* str,size_t size)

{

     size_t i = 0;

     while( i < size )

     {

            str[i] -= 3;

            i++;

     }

}

 

결론: 파일 안에서 글자 수에 따른 범위를 정할때는 index < size 방식이 제일 안전함

반응형
반응형

EX01_읽기 엑세스 위반

 

 

 

원인 : 배열의 인덱스를 벗어난 주소를 찾아서, 금지된 영역에(kernal 영역) 엑세스 하려고 했기 때문에

 

해결 : 배열이 충분히 사이즈가 크게 만들던지, 배열을 가져오는 함수에서 제한 범위를 벗어나지 않게 해야 한다

반응형
반응형

Singleton Pattern (싱글톤 패턴)

프로그램안에서 어떤 클래스의 인스턴스가 1개만 존재 하도록, 폐쇄적으로 클래스를 디자인 하는것

 

 

구현방법

1.생성자는 private 으로 막는다, 외부에서 new 를 통한 instance 생성을 할 수 없게 만든다.

 

 

 

 

2.인스턴스 하나를 담을 수 있는 포인터변수를 선언, static 으로 설정해서, 오직하나만 존재할 수 있게 만든다

 

 

 

 

 

 

3. m_pInst를 가져오거나(get), 메모리 해제(Destroy)할 수 있는 멤버 함수들을 선언, static 변수에 접근할 수 있어야 하고

외부에서 해당 함수들을 쓸 수 있어야 하므로 public 으로 지정

 

 

 

 

 

 

 

MySingletonClass.cpp

 

4. m_pInst를 초기화 해주기 위해서는 static 멤버 변수 이므로, 생성자가 아닌 클래스 외부에서 

MySingletonClass* MySingletonClass::m_pInst = nullptr; //이런식으로 초기화를 해준다

 

 

5.GetInst() 함수를 구현한다, m_pInst 가 nullptr 이라면, 새로 생성하여 instance를 초기화 해준뒤

앞으로도 호출될때마다 이미 생성된 instance를 return 하도록 한다

 

 

6.DestroyInst() 함수를 구현한다, GetInst() 함수와 유사한 구조를 가지고 있다 차이점은

delete와 nullptr, 초기화 가 return 대신에 들어간다

 

 

 

최종코드

MySingletonClass.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
class MySingletonClass
{
private:
    MySingletonClass();
    ~MySingletonClass();
 
private:
    static MySingletonClass* m_pInst;
 
public:
    static MySingletonClass* GetInst();
    static void DestroyInst();
 
};
 
cs

 

MySingletonClass.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "MySingletonClass.h"
 
MySingletonClass* MySingletonClass::m_pInst = nullptr;
 
MySingletonClass::MySingletonClass()
{
}
 
MySingletonClass::~MySingletonClass()
{
}
 
MySingletonClass* MySingletonClass::GetInst()
{
    if (!m_pInst)
    {
        m_pInst = new MySingletonClass;
    }
    return m_pInst;
}
 
void MySingletonClass::DestroyInst()
{
    if (!m_pInst)
    {
        return;
    }
    delete m_pInst;
    m_pInst = nullptr;
 
}
 
cs
반응형
반응형

const

  • Lvalue로 올 수 없는 변수(상수), 주소 또는 역참조값이 Lvalue로 올 수 없는 포인터 변수등 선언할 쓰임
  • 포인터 변수를 선언할때, 자료형 앞 또는 포인터 변수 이름 앞 또는 두위치 모두 "const" keyword 를 붙이면, 각각의 위치에 따라서, 값또는 주소 혹은 둘다, Lvalue로 올 수 없음, 대입 연산자 왼쪽에 올 수 없음
  • 이때 주의해야 될것은, 어떤 특정 변수를 대상으로 하는게 아니라, 자료형, 자료형* 포인터  를 대상으로 하는 것이다, 즉 const int a 가 있다면, int a를 const 로 만든게 아니라, a 가 const int 타입이며, 다른 const 자료형 처럼 Lvalue로 올 수 없는 것이지 값을 수정할 수 없는게 아니다.
  • constexpr과는 다르게, 값이 컴파일타임 뿐만 아니라 런타임에도 값이 정해질 있음, 둘다 허용
    • 선언과 동시 초기화를 하면 컴파일타임(Compile-time)

 

  • 선언  런타임에 초기화를 하면 런타임(Run-time)

 

 

 

const 자료형 변수식별자 = 초기화값;

값   수정   불가능

 

 

const 자료형& 레퍼런스식별자 = 변수;

레퍼런스   변수   역시   동일 ,  값을   수정할   수   없음

 

 

 

 

포인터 변수에 붙일 경우

1. const 자료형 *포인터식별자 = &변수;

자료형 앞에 붙는 경우 역참조값 수정 불가능

 

2. 자료형 * const 포인터식별자 = &변수;

포인터 변수 식별자(이름) 앞에 붙는 경우,역참조값 수정가능, 가리키는 주소 수정 불가능

 

 

 

3. const 자료형 * const 포인터 식별자 = &변수

자료형앞 ,  포인터 변수 식별자(이름)앞, 역참조값, 가리키는 주소,  둘 다 수정 불가능

 

또한 멤버 함수 뒤에 const 붙일경우, 해당 함수는 멤버 변수를 수정할 없다

반응형
반응형

Static Function (정적 함수)

  •  .cpp 파일내에 선언 정의가 함께 있으며, .cpp 파일내에서만 사용가능

 

Static Member Function (정적 멤버 함수)

  • C++ 에서는 클래스의 멤버 함수또한 정적으로 선언 가능
  • static member function 클래스의 객체를 생성하지 않고도클래스 이름만으로 호출 가능
  • 객체를 생성하지 않으므로, this 포인터를 가지지 않음
  • 특정 객체와 결합하지 않으므로, 정적 멤버 변수 밖에 사용할 없음ex1)

static 멤버 변수의 초기화는 클래스 외부에서 한다

위 그림에서 보이는것처럼 nonstatic member function 에서는 비정적멤버 변수, 정적 멤버변수 둘다 접근 가능하다.

그러나

"비 정적 멤버 참조는 특정 객체에 상대적 이어야 합니다"

 Static Member Function(정적 멤버 함수) 에서는, 비정적멤버 변수에 접근할려고 할경우 에러가 뜬다

따라서 오직 정적 멤버 변수(static member variable)만 접근이 가능하다

 

또한 private 인경우, static 이라 할지라도, 클래스 외부에서 사용 불가능하다

private 로 바꿨더니 호출이 불가능하다

 

private:

static member function

클래스 스코프 내부에서만 사용가능

public:

static member function

클래스 스코프 내부 외부에서

객체 생성하지 않고 사용가능

static function

.cpp 파일 내에서만 사용가능, 선언과 정의
둘다
.cpp 있어야함

 

반응형

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

c++ Singleton Pattern 기본 구현 방법  (0) 2020.03.03
const  (0) 2020.02.29
CopyConstructor, Shallow Copy, Deep Copy  (0) 2020.02.24
std::function (c++ 11)  (0) 2020.02.23
Input Output library  (0) 2020.02.21
반응형

Copy Constructor (복사 생성자)

자기 자신(객체)과 같은 자료형의 instance 매개변수로 받으며 

매개변수로 받는 instance의 데이터들을 복사해서 그대로 자기자신(객체)의 데이터들에 대입하는 생성자 함수

 

어떤 클래스를 디자인하는데, Copy Constructor(복사생성자)를 구현해 놓지 않고

 

A a;

A a_2 = a;

 

위와 같이 copy initialization 경우, 컴파일러가 자동으로 default 복사 생성자를 만들어 준다

 그러나 default copy constructor Shallow Copy 동작하므로 유의하며 쓰던지, copy contructor assignment operator 따로 구현하여, 그안에서 deep copy 되도록 하여야 한다

 

 

Shallow Copy (주소값도 그대로 복사)

객체를 복사할때, default 복사 생성자를 이용할 경우, 객체안의 멤버 변수들이 전부 복사 된다 이때

변수들이 Primitive types(int, char, bool, float, double, 값형) 경우, 값들을 그대로 복사해도 문제가 되지 않는다, 그러나 class struct, 포인터 변수, 등등 객체 또는 메모리의 주소를 가리키는 경우는, 가리키는 메모리 주소를 그대로 복사하는 꼴이 되버려서, 원본 또는 복사본 둘중 하나가 delete 경우, 다른 한쪽에도 똑같은 영향을 미치는 것이다, 왜냐하면 서로 같은 주소를 바라보고 있기 때문이다

 

ex1)

 

 

코드를 보면 hello 라는 객체를 선언 한뒤 "hello" 생성자를 통해 초기화 했다

copy 라는 객체를 선언하고 hello copy initialize 했는데, 이때 copy constructor 구현되있지 않기 때문에 컴파일러는 default copy constructor 구현하여 실행시킨다

그리고 값만을 복사하는 shallow copy 진행된다

만약 primitive type 이라면 상관 없지만, 주소를 대입해야 하는 포인터

타입 이라면, 주소를 복사해버리게 된다

아래와 같이 같은 주소를 공유하게 되는 사태가 벌어지는 것이다

 

copy.m_Data = hello.m_Data;

 

 

Debug 위해서 코드를 좀더 추가해서 다시 출력해보면

역시나 둘의 주소가 같다는걸 있다.

 

 

이렇게 되면, hello.m_Data 또는 copy.m_Data 둘중 하나가 delete 되면

다른 쪽에서도 delete 된것과 같은 것이다

scope 벗어나게 되면서 copy 자동으로 소멸되고, 소멸자를 실행해

delete[] copy.m_Data; 실행해 delete[] hello.m_Data; 실행한 것과 같은 결과가 나오고

hello.GetString(); 통해 hello.m_Data 접근하여도 이미 delete 되어 메모리 반환 되었기 때문에 쓰레기 값이 나오게 된다

 

정리하자면 멤버 변수로 포인터 또는 어떤 객체의 주소를 참조하는 경우

default contructor 사용금지

Shallow Copy(값만 그대로 복사) 금지

Deep Copy 해야한다

 

 

 

 

 

Deep Copy

(주소를 새로 할당하고 새로 할당된 객체에 값들을 복사)

class struct, 포인터 변수, 등등 객체 또는 메모리의 주소를 가리키는 경우는, 가리키는 메모리 주소는 복사 하지 않고 새로 동적할당을 한다, 그리고 원본의 주소가 가리키는 값들을 새로 할당된 객체에 복사한다, copy constructor 대입연산자를 따로 구현하여 default constructor 실행되지 않게 하는 것이다

 

 

ex1) Copy Constructor 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <cassert>
 
class MyString
{
private:
    char* m_Data = nullptr;
    int m_length = 0;
 
public:
    MyString(const char* _source = "")
    {
        assert(_source);
 
        m_length = std::strlen(_source) + 1;
        m_Data = new char[m_length];
 
        strcpy_s(m_Data, m_length, _source);
        m_Data[m_length - 1= '\0';
    }
//Copy Constructor
    MyString(const MyString& _source)
    {
        std::cout << "User defined Copy Constructor called" << std::endl;
        m_length = _source.m_length;
        if (_source.m_Data != nullptr)
        {
            if (m_Data)
            {
                delete[] m_Data;
                m_Data = nullptr;
            }
            //Deep copy
            m_Data = new char[m_length];
            strcpy_s(m_Data, m_length, _source.m_Data);
            m_Data[m_length - 1= '\0';
        }
        else
        {
            m_Data = nullptr;
        }
    }
 
    ~MyString()
    {
        delete[] m_Data;
    }
 
    char* GetString() { return m_Data; }
    char& GetDataRef(){ return *m_Data; }
    int GetLength() { return m_length; }
};
 
int main()
{
    MyString hello("hello");
    {
        MyString copy = hello;
        char& helloDataRef = hello.GetDataRef();
        char& copyDataRef = copy.GetDataRef();
        const char* result = &helloDataRef == &copyDataRef ? "true" : "false";
        printf("Copy's &m_Data == hello's &m_Data : %s\n", result);
        printf("Copy's &m_Data : 0x%p\n"&helloDataRef);
        printf("hello's &m_Data : 0x%p\n"&copyDataRef);
    } 
 
    std::cout << hello.GetString() << std::endl;
}
cs

 

결과는

 

 

사용자가 정의가 Copy Constructor 호출됐으며

hello, copy, 각각의 데이터 주소가 별개의 주소를 가리키고 있으며

copy 소멸되었어도 hello.m_Data delete 된것은 아니기 때문에

쓰레기 값이 아닌 온전한 데이터가 출력이 된다

 

그러나 Shallow Copy

선언후 동시 초기화 뿐만 아니라

초기화만 하는 상황

 

 

코드와 같이 같은 타입의 객체를 다음 줄에 대입할때도 실행이 된다

 

MyString str2; //선언

str2 = hello; //초기화, 같은 타입 객체 대입

 

이때는 Copy Constructor 구현해놨다 하더라도 에러가 발생한다

따라서 아래처럼 대입연산자(Assignment operator)를 구현해야 한다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <iostream>
#include <cassert>
 
class MyString
{
private:
    char* m_Data = nullptr;
    int m_length = 0;
 
public:
    MyString(const char* _source = "")
    {
        assert(_source);
 
        m_length = std::strlen(_source) + 1;
        m_Data = new char[m_length];
 
        strcpy_s(m_Data, m_length, _source);
        m_Data[m_length - 1= '\0';
    }
 
    MyString(const MyString& _source)
    {
        std::cout << "User defined Copy Constructor called" << std::endl;
        m_length = _source.m_length;
        if (_source.m_Data != nullptr)
        {
            if (m_Data)
            {
                delete[] m_Data;
                m_Data = nullptr;
            }
            //Deep copy
            m_Data = new char[m_length];
            strcpy_s(m_Data, m_length, _source.m_Data);
            m_Data[m_length - 1= '\0';
        }
        else
        {
            m_Data = nullptr;
        }
    }
 
    //Assignment Operator
    MyString& operator = (const MyString& _source)
    {
        std::cout << "Assignment operator" << std::endl;
        //
        //if (this == &_source) //prevent self-assignment
        //    return *this;
 
        if (m_Data)
        {
            delete[] m_Data;
            m_Data = nullptr;
        }
 
        m_length = _source.m_length;
 
        if (_source.m_Data != nullptr)
        {
            m_Data = new char[m_length];
            strcpy_s(m_Data, m_length, _source.m_Data);
            m_Data[m_length - 1= '\0';
            return *this;
        }
        else
        {
            m_Data = nullptr;
            return *this;
        }
 
    }
 
 
 
    ~MyString()
    {
        delete[] m_Data;
    }
 
    char* GetString() { return m_Data; }
    char& GetDataRef(){ return *m_Data; }
    int GetLength() { return m_length; }
};
 
int main()
{
    MyString hello("hello");
    {
        MyString copy; 
        copy = hello;
        char& helloDataRef = hello.GetDataRef();
        char& copyDataRef = copy.GetDataRef();
        const char* result = &helloDataRef == &copyDataRef ? "true" : "false";
        printf("Copy's &m_Data == hello's &m_Data : %s\n", result);
        printf("Copy's &m_Data : 0x%p\n"&helloDataRef);
        printf("hello's &m_Data : 0x%p\n"&copyDataRef);
    } 
 
    std::cout << hello.GetString() << std::endl;
}
cs

 

 

//Assignment Operator 부분을 추가 시키면 다시 정상 작동된다

 

 

그런데 대입연산자(Assignment Operator) 구현할때 주의할 점은

 

 

if (this == &_source) //prevent self-assignment

return *this;

 

위코드를 반드시 붙여줘야 한다, 자기 자신을 복사하게 만드는

hello = hello;

막는 것이다, 자기 자신을 Rvalue 놓고 Lvalue 자기자신에게

대입하게 되면 Lvalue 원래 있던 자기 자신의 데이터를 지울 것이고

지우게 되면 Rvalue 데이터도 지워져서 결국 지워지는 효과가 나올 있다

(물론 의도하던 안하던, 애초에 hello = hello; 지우는 코드로 쓰는 사람은

없을 것이고, 어떤 결과가 나올지 예측하기도 힘들다)

 

어쨌든 Copy Constructor, Assignment Operator 둘다 구현해 놓는 것을 권장한다

반응형

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

c++ Singleton Pattern 기본 구현 방법  (0) 2020.03.03
const  (0) 2020.02.29
Static Member Function(정적 멤버 함수)  (0) 2020.02.27
std::function (c++ 11)  (0) 2020.02.23
Input Output library  (0) 2020.02.21
반응형

std::function (c++ 11)

#include <functional>

c++11 부터 지원됨

함수 포인터 변수 역할을 해줌

 

 

 

사용법

 

//function 객체 선언

std::function<함수리턴타입(인자타입)>  function객체식별자;  

 

function객체식별자 = std::bind(함수이름);

 

ex1)

 

 

위와 같은 방식으로 사용하면 되고

 

 

멤버 함수를 초기화 호출할떄는

 

//function 객체 선언

std::function<함수리턴타입(인자타입)>  function객체식별자;  

 

 

//초기화

function객체식별자 = std::bind(&클래스식별자::함수이름, 인스턴스);

 

function객체식별자(); //호출

 

ex2)

 

 

 

ex3) 또한 인자가 있는 경우 placeholder 있다

이때 반드시 인자 타입이 일치해야 한다

 

ex4) 인자와 리턴이 있는 멤버 함수

 

반응형

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

c++ Singleton Pattern 기본 구현 방법  (0) 2020.03.03
const  (0) 2020.02.29
Static Member Function(정적 멤버 함수)  (0) 2020.02.27
CopyConstructor, Shallow Copy, Deep Copy  (0) 2020.02.24
Input Output library  (0) 2020.02.21
반응형

std::ios_base

  • stream input output 형식 관련 데이터를 처리함(정수형을 출력시 10진수로 할지 16진수로 할지 등을 처리
  • 모든 입출력 클래스는 ios_base base 클래스로 두고있음

 

 

 

std::ios

  • stream buffer 초기화
  • 입출력 작업의 상태를 처리(파일의 끝에 도달했는지를 있음, eof() 함수

 

std::istream, std::ostream

  • ios_base, ios 입출력 작업 상태, 데이터 처리를 했다면
  • istream, ostream 각각 실제로 입력 출력을 수행함
  • cin istream 클래스의 instance 이다, 연산자 >> 오버로딩이 되어있고 모든타입에 되어 있어서, 입력 가능
  • 그러나, cin(istream) 은 공백문자를 무시하고, \n 기준으로 입력을 그만받음
  •  
  • cout 또한 ostream 클래스의 instance 이며, 연산자 << 오버로딩이 되어있고
  • 모든타입에 되어 있어서, 모든타입이 출력 가능함
  • http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/

 

std::ifstream

  • istream 상속 받음
  • filebuf 객체를 내부 스트림 버퍼로 사용
  • 연결된 파일에 istream에서 상속받은 입력 함수들을 있음
  • input 가능한 filebuf 객체 (input filebuf stream)

 

std::ofstream

  • ostream 상속 받음
  • filebuf 객체를 내부 스트림 버퍼로 사용
  • 연결된 파일에 ostream에서 상속받은 출력 함수들을 있음
  • output 가능한 filebuf 객체 (output filebuf stream)

 

std::iostream

  • istream, ostream 상속 받음 (입력,출력 둘다 가능)

 

std::fstream

  • iostream 상속 받음(입력, 출력 둘다 가능)
  • filebuf 객체를 내부 스트림 버퍼로 사용
  • 연결된 파일에 iostream에서 상속받은 입력 출력 함수들을 있음
반응형

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

c++ Singleton Pattern 기본 구현 방법  (0) 2020.03.03
const  (0) 2020.02.29
Static Member Function(정적 멤버 함수)  (0) 2020.02.27
CopyConstructor, Shallow Copy, Deep Copy  (0) 2020.02.24
std::function (c++ 11)  (0) 2020.02.23

+ Recent posts