1. 코딩 스탠다드
- 코드를 짤때 더 가독성 좋은, 유지보수 할 수 있는 코드를 만들고 싶어서 C++ 코딩 스탠다드에 대해 공부해 보았다.
- https://gbleem.tistory.com/13
C++ 코딩 스탠다드
0. 코딩 스탠다드를 지켜보자코딩을 하다보니 이름 규칙이나 변수명 등을 정리하지 못하고 짓고 있는 것 같아서 이번 과제를 하면서는 코딩 스탠다드를 지켜보자는 생각에 C++ 코딩 스탠다드를
gbleem.tistory.com
2. 템플릿
- ch2 3번 과제를 하던 도중
- 템플릿을 이용한 클래스를 만드는데, 선언을 .h에 하고 구현을 .cpp에 하니 문제가 발생하였다.
- 이를 해결하고 원인에 대해 공부해 보았다.
- https://gbleem.tistory.com/14
C++ 템플릿 - 헤더파일에서 구현하자
과제를 하던 도중, 템플릿을 사용하여 vector 클래스를 만들고 있는데 .h 파일에서 정의를 하고 .cpp에서 구현을 하였더니 컴파일러가 링크 에러를 띄워주었다. (LNK1120)이 문제점을 분석하고, 찾은
gbleem.tistory.com
3. 과제 풀이
- 필수 기능 구현
- SimpleVector.h 와 main.cpp의 모습
- 위에서 언급한대로 템플릿으로 만들어진 클래스의 구현은 헤더파일에서 하는 것이 좋다.
#pragma once
#include <iostream>
template <typename T>
class SimpleVector
{
public:
SimpleVector();
SimpleVector(int capacity);
~SimpleVector();
void PushBack(const T& value);
void PopBack();
int GetSize()
{
return mCurrentSize;
}
int GetCapacity()
{
return mcurrentCapacity;
}
void Print()
{
if (mCurrentSize == 0)
std::cout << "EMPTY VECTOR";
for (int i = 0; i < mCurrentSize; ++i)
{
std::cout << mData[i] << " ";
}
std::cout << "\n";
}
private:
T* mData;
int mCurrentSize;
int mcurrentCapacity;
};
template <typename T>
SimpleVector<T>::SimpleVector()
:mcurrentCapacity(10)
, mCurrentSize(0)
{
mData = new T[10];
}
template <typename T>
SimpleVector<T>::SimpleVector(int capacity)
:mcurrentCapacity(capacity)
, mCurrentSize(0)
{
mData = new T[capacity];
}
template<typename T>
SimpleVector<T>::~SimpleVector()
{
mcurrentCapacity = 0;
mCurrentSize = 0;
delete[] mData;
}
template<typename T>
void SimpleVector<T>::PushBack(const T& value)
{
if (mCurrentSize >= mcurrentCapacity)
{
std::cout << "not enough capacity\n";
return;
}
mData[mCurrentSize] = value;
mCurrentSize++;
}
template<typename T>
void SimpleVector<T>::PopBack()
{
if (mCurrentSize == 0)
{
std::cout << "Empty vector!!\n";
return;
}
mCurrentSize--;
}
#include "SimpleVector.h"
int main()
{
SimpleVector<int> vector(5);
vector.PushBack(10);
vector.PushBack(20);
vector.PushBack(30);
vector.PushBack(40);
vector.PushBack(50);
vector.Print(); //10 20 30 40 50
vector.PopBack();
vector.Print(); //10 20 30 40
vector.PopBack();
vector.Print(); //10 20 30
vector.PopBack();
vector.Print(); //10 20
vector.PopBack();
vector.Print(); //10
vector.PopBack();
vector.Print(); // EMPTY VECTOR
vector.PopBack(); //Empty vector!!
vector.Print(); //EMPTY VECTOR
vector.PushBack(100);
vector.PushBack(200);
vector.PushBack(300);
vector.Print(); //100 200 300
return 0;
}
- 도전 기능 구현
- 동작은 제대로 하는데, 메모리 누수 체크를 해보는 도중 메모리 누수가 발생한다고 떠서 좀 더 수정이 필요해 보인다.
- 메모리 누수 체크를 하는 코드를 아직 정확하게 이해하지 못해서 그런것인지, 아니면 진짜 누수가 일어나는 것인지 확인이 필요하다.
#pragma once
#define _CRTDBG_MAP_ALLOC
#include <algorithm>
#include <iostream>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
template <typename T>
class BetterSimpleVector
{
public:
BetterSimpleVector();
BetterSimpleVector(int capacity);
BetterSimpleVector(const BetterSimpleVector& other);
~BetterSimpleVector();
void PushBack(const T& value);
void PopBack();
void Print();
void SortData();
int GetSize()
{
return mCurrentSize;
}
int GetCapacity()
{
return mCurrentCapacity;
}
protected:
void Resize(int newCapacity);
private:
T* mData;
int mCurrentCapacity;
int mCurrentSize;
};
template <typename T>
BetterSimpleVector<T>::BetterSimpleVector()
: mCurrentCapacity(10)
, mCurrentSize(0)
{
mData = new T[10];
}
template <typename T>
BetterSimpleVector<T>::BetterSimpleVector(int capacity)
: mCurrentCapacity(capacity)
, mCurrentSize(0)
{
mData = new T[capacity];
}
template<typename T>
BetterSimpleVector<T>::BetterSimpleVector(const BetterSimpleVector& other)
{
mCurrentCapacity = other.mCurrentCapacity;
mCurrentSize = other.mCurrentSize;
mData = new T[mCurrentCapacity];
for (int i = 0; i < mCurrentSize; ++i)
{
mData[i] = other.mData[i];
}
}
template<typename T>
BetterSimpleVector<T>::~BetterSimpleVector()
{
mCurrentCapacity = 0;
mCurrentSize = 0;
delete[] mData;
_CrtDumpMemoryLeaks();
}
template<typename T>
void BetterSimpleVector<T>::PushBack(const T& value)
{
//full
if (mCurrentSize == mCurrentCapacity)
{
Resize(mCurrentCapacity + 5);
}
mData[mCurrentSize] = value;
mCurrentSize++;
}
template<typename T>
void BetterSimpleVector<T>::PopBack()
{
if (mCurrentSize == 0)
{
std::cout << "Empty vector!!\n";
return;
}
mCurrentSize--;
}
template<typename T>
void BetterSimpleVector<T>::Print()
{
if (mCurrentSize == 0)
{
std::cout << "EMPTY VECTOR";
return;
}
for (int i = 0; i < mCurrentSize; ++i)
{
std::cout << mData[i] << " ";
}
std::cout << "\n";
}
template<typename T>
void BetterSimpleVector<T>::SortData()
{
std::sort(mData, mData + mCurrentSize);
}
template<typename T>
void BetterSimpleVector<T>::Resize(int newCapacity)
{
if (newCapacity <= mCurrentCapacity)
{
std::cout << "we have remain capacity\n";
return;
}
std::cout << "Resize Vector, current capacity is " << newCapacity << "\n";
T* newData = new T[newCapacity];
//현재 값 복사
for (int i = 0; i < mCurrentSize; ++i)
{
newData[i] = mData[i];
}
delete[] mData;
mData = newData;
mCurrentCapacity = newCapacity;
_CrtDumpMemoryLeaks();
}
#include <iostream>
#include "SimpleVector_v2.h"
int main()
{
BetterSimpleVector<int> vector2;
BetterSimpleVector<int> vector(3);
vector.PushBack(10);
vector.PushBack(40);
vector.PushBack(30);
vector.PushBack(50);
vector.PushBack(20);
std::cout << "vector: ";
vector.Print();
vector2.PushBack(100);
vector2.PushBack(200);
vector2.PushBack(300);
vector2.PushBack(400);
vector2.PushBack(500);
vector2.PushBack(600);
vector2.PushBack(700);
vector2.PushBack(800);
vector2.PushBack(900);
vector2.PushBack(1000);
vector2.PushBack(1100);
std::cout << "vector2: ";
vector2.Print();
BetterSimpleVector<int> newVector(vector2);
std::cout << "----COPY CONSTRUCTOR TEST----\n";
std::cout << "newVector by vector2: ";
newVector.Print();
std::cout << "---------------------\n";
BetterSimpleVector<int> vector3(3);
vector3.PushBack(1);
vector3.PushBack(2);
vector3.PushBack(3);
std::cout << "vector3: ";
vector3.Print();
BetterSimpleVector<int> newVector2(vector3);
std::cout << "----COPY CONSTRUCTOR TEST----\n";
std::cout << "newVector2 by vector3: ";
newVector2.Print();
std::cout << "---------------------\n";
newVector2.PushBack(4);
newVector2.PushBack(5);
newVector2.PushBack(6);
std::cout << "newVector2: ";
newVector2.Print();
vector3.PushBack(1);
std::cout << "vector3: ";
vector3.Print();
return 0;
}
4. 내일 할 것
- const 키워드 정리
- 메모리 누수 체크 코드 공부 및 과제에서 발생한 문제점을 찾기 (해결)
- inline 함수 공부
5. 메모리 누수 체크
- 뭐가 잘못된 것이지 좀 더 찾아보다가 해결책을 찾게 되었다.
- 위의 코드에서 메모리 누수가 발생한 것은 내가 잘못된 곳에서 _CrtDumpMemoryLeaks() 를 호출했기 때문이다.
- main 에서 프로그램 종료시 호출되도록 구현해야 제대로 된 memory leak을 찾을 수 있다.
- 관련 코드 정리해 보자면,
- 우선 위의 코드에서 _CrtDumpMemoryLeaks()는 다 없애버려야 한다.
- 헤더 파일에 new 매크로를 사용해서, 메모리 누수가 발생한 곳의 위치를 알려주는 코드를 추가한다.
- main 함수에 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);를 적어주면, 추가적인 다른 처리없이 프로그램 종료 시 메모리 누수 발생 시 어디서 발생한 것인지 알려주게 된다.
//header file
#define _CRTDBG_MAP_ALLOC
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
...
//main.cpp
...
int main()
{
#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
...
}
- 아래에서 어떤 식으로 메모리 누수를 알려주는 지 예시를 통해 확인해보자
- 왼쪽은 .h 파일이고 오른쪽은 .cpp 파일이다.
- 위에서 언급한 대로 구성한 코드에 아래 처럼 강제로 메모리 누수가 발생하는 코드를 넣으면
- 아래 이미지처럼 메모리 누수가 발생했고, 몇번째 줄에서 발생했는지 알려주게 된다.
- 저 코드를 main에서 주석처리해버리면 아래처럼 메모리 누수가 일어나지 않는 것을 알 수 있다.
- cf) 코드를 추가하고 나서 비주얼 스튜디오의 "빌드 -> 솔루션 다시 빌드" 를 해줘야 수정한 것이 제대로 적용되는 것 것 같다.
- 결론적으로 위에서 완성한 코드는 메모리 누수가 없는 코드라고 생각이 되었다. 그래도 혹시 모르니 제출 전 한번 더 체크해 볼 예정이다.
'C++' 카테고리의 다른 글
C++ TIL day 11 (포인터 연산 문제) (2) | 2024.12.31 |
---|---|
const 키워드 (0) | 2024.12.31 |
C++ 템플릿 - 헤더파일에서 구현하자 (0) | 2024.12.30 |
C++ 코딩 스탠다드 (2) | 2024.12.30 |
C++ TIL day 9 (3) | 2024.12.27 |