Rule of Five : 클래스에서 동적 할당 메모리를 사용하고 있다면 소멸자, 복제 생성자, 이동 생성자, 복제 대입 연산자, 이동 대입 연산자를 반드시 구현한다.
Rule of Zero : 모던 C++로 작성할 경우 raw pointer 대신 STL의 std::vector나 스마트 포인터를 사용해 위의 5가지를 구현하지 않아도 괜찮도록 작성하는 것을 권장한다.
raw pointer를 이용한 matrix 클래스를 사용한다.
template<typename T>
class Matrix
{
public:
Matrix(size_t height, size_t width)
: mHeight(height), mWidth(width)
{
mData = new T * [mHeight];
for (size_t i = 0; i < mHeight; ++i)
{
mData[i] = new T[mWidth];
}
}
T& at(size_t row, size_t col) { return mData[row][col]; }
private:
size_t mHeight = 0;
size_t mWidth = 0;
T** mData = nullptr;
};
base class의 경우 memory leak이 발생한다. 소멸자에서 mData에 할당된 메모리를 해제해주어야 한다.
~Matrix()
{
clear();
}
void clear() noexcept
{
for (size_t i = 0; i < mHeight; ++i)
{
delete[] mData[i];
}
delete[] mData;
mData = nullptr;
mHeight = 0;
mWidth = 0;
}
Matrix(const Matrix& src)
: Matrix(src.mHeight, src.mWidth)
{
for (size_t row = 0; row < mHeight; ++row)
{
for (size_t col = 0; col < mWidth; ++col)
{
mData[row][col] = src.mData[row][col];
}
}
}
Matrix<int> mat1(3, 3);
Matrix<int> mat2(mat1); // mat1과 동일한 값(deep copy)을 가지는 mat2가 생성됨.
Matrix& operator=(const Matrix& rhs)
{
if (this == &rhs)
{
return *this;
}
Matrix temp(rhs);
swap(*this, temp);
return *this;
}
void swap(Matrix& first, Matrix& second) noexcept
{
std::swap(first.mHeight, second.mHeight);
std::swap(first.mWidth, second.mWidth);
std::swap(first.mData, second.mData);
}
Matrix<int> mat1(3, 3);
auto mat2 = mat1;
Matrix(Matrix&& src) noexcept
{
moveFrom(src);
}
void moveFrom(Matrix& src) noexcept
{
mHeight = src.mHeight;
mWidth = src.mWidth;
mData = src.mData;
src.mHeight = 0;
src.mWidth = 0;
src.mData = nullptr;
}
Matrix<int> mat(5, 5);
auto mat2(std::move(mat));
Matrix& operator=(Matrix&& rhs) noexcept
{
if (this == &rhs)
{
return *this;
}
clear();
moveFrom(rhs);
return *this;
}
Matrix<int> mat(5, 5);
auto mat2 = std::move(mat);
template<typename T>
class Matrix
{
public:
Matrix(size_t height, size_t width)
: mHeight(height), mWidth(width)
{
mData = new T * [mHeight];
for (size_t i = 0; i < mHeight; ++i)
{
mData[i] = new T[mWidth];
}
}
// 1. 소멸자
~Matrix()
{
clear();
}
// 2. 복제 생성자
Matrix(const Matrix& src)
: Matrix(src.mHeight, src.mWidth)
{
for (size_t row = 0; row < mHeight; ++row)
{
for (size_t col = 0; col < mWidth; ++col)
{
mData[row][col] = src.mData[row][col];
}
}
}
// 3. 복제 대입 연산자
Matrix& operator=(const Matrix& rhs)
{
if (this == &rhs)
{
return *this;
}
Matrix temp(rhs);
swap(*this, temp);
return *this;
}
// 4. 이동 생성자
Matrix(Matrix&& src) noexcept
{
moveFrom(src);
}
// 5. 이동 대입 연산자
Matrix& operator=(Matrix&& rhs) noexcept
{
if (this == &rhs)
{
return *this;
}
clear();
moveFrom(rhs);
return *this;
}
T& at(size_t row, size_t col) { return mData[row][col]; }
private:
void swap(Matrix& first, Matrix& second) noexcept
{
std::swap(first.mHeight, second.mHeight);
std::swap(first.mWidth, second.mWidth);
std::swap(first.mData, second.mData);
}
void clear() noexcept
{
for (size_t i = 0; i < mHeight; ++i)
{
delete[] mData[i];
}
delete[] mData;
mData = nullptr;
mHeight = 0;
mWidth = 0;
}
void moveFrom(Matrix& src) noexcept
{
mHeight = src.mHeight;
mWidth = src.mWidth;
mData = src.mData;
src.mHeight = 0;
src.mWidth = 0;
src.mData = nullptr;
}
size_t mHeight = 0;
size_t mWidth = 0;
T** mData = nullptr;
};