인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

jjk0806님의 프로필 이미지
jjk0806

작성한 질문수

홍정모의 따라하며 배우는 C++

컨테이너 클래스 IntArray 과제 피드백 요청

작성

·

20

1

안녕하세요 10.6 컨테이너 클래스 강의에 IntArray 구현해보았는데 피드백 요청드립니다.

잘못된 곳이라던가 좀 더 공부가 필요한 부분 지적해주시면 너무 감사드립니다.

#include <iostream>
#include <initializer_list>

class IntArray
{
private:
	int m_length = 0;
	int* m_data = nullptr;

public:
	IntArray(const std::initializer_list<int> number)
	{
		m_length = number.size();
		m_data = new int[m_length];

		int count = 0;
		for (auto& arr : number)
		{
			if (count < m_length)
			{
				m_data[count] = arr;
				++count;
			}
		}
	}

	IntArray(const IntArray& copy)
	{
		m_length = copy.m_length;
		m_data = new int[m_length];

		for (int i = 0; i < m_length; i++)
			m_data[i] = copy.m_data[i];

		std::cout << "복사 생성자 호출" << std::endl;
	}

	~IntArray()
	{
		delete[] m_data;
		std::cout << "메모리 해제" << std::endl;
	}

	void reset()
	{
		if (m_data != nullptr)
		{
			m_length = 0;
			delete[] m_data;
			m_data = nullptr;
		}
	}

	void resize(const int& size)
	{
		int* temp_data = new int[size];
		for (int i = 0; i < size; i++)
		{
			temp_data[i] = m_data[i];
			if (i >= m_length)
			{
				temp_data[i] = 0;
			}
		}

		delete[] m_data;
		m_length = size;
		m_data = temp_data;
	}

	void insertBefore(const int& insert, const int& before)
	{
		if (before < 0 || before > m_length)
		{
			std::cout << "배열의 크기 확인" << std::endl;
			return;
		}

		int* temp_data = new int[m_length + 1];

		for (int i = 0, j = 0; i < m_length + 1; i++)
		{
			if (i == before)
			{
				temp_data[i] = insert;
			}
			else
			{
				temp_data[i] = m_data[j++];
			}
		}

		delete[] m_data;
		m_data = temp_data;
		m_length++;
	}

	void remove(const int& number)
	{
		if (number < 0 || number > m_length)
		{
			std::cout << "배열의 크기 확인" << std::endl;
			return;
		}

		int* temp_data = new int[m_length - 1];

		for (int i = 0, j = 0; i < m_length; i++)
		{
			if (i != number)			
				temp_data[j++] = m_data[i];			
		}

		delete[] m_data;
		m_data = temp_data;
		m_length--;
	}

	void push_back(const int& number)
	{
		int* temp_data = new int[m_length + 1];

		for (int i = 0; i < m_length; i++)
			temp_data[i] = m_data[i];

		temp_data[m_length] = number;

		delete[] m_data;
		m_data = temp_data;
		m_length++;
	}

	friend std::ostream& operator << (std::ostream& out, const IntArray& arr)
	{		
		for (int i = 0; i < arr.m_length; i++)
		{
			out << arr.m_data[i] << " ";
		}
		return out;
	}

};

int main()
{
	IntArray my_arr{ 1, 3, 5, 7, 9 };

	my_arr.insertBefore(10, 1);
	std::cout << my_arr << std::endl;

	my_arr.remove(3);
	std::cout << my_arr << std::endl;

	my_arr.push_back(13);
	std::cout << my_arr << std::endl;
}

답변 2

1

안녕하세요? 질문&답변 도우미 Soobak 입니다.

 

메모리 접근과 관련된 일부 부분을 제외하고, 전반적으로 잘 구현하셨습니다. 👍

 

꼼꼼히 살펴보고 피드백 드려봅니다.

void resize(const int& size)
{
    int* temp_data = new int[size];
    for (int i = 0; i < size; i++)
    {
        temp_data[i] = m_data[i];
        if (i >= m_length)
        {
            temp_data[i] = 0;
        }
    }

    delete[] m_data;
    m_length = size;
    m_data = temp_data;
}

: resize() 함수의 구현에 있어서 기존의 크기보다 새롭게 할당하는 크기가 큰 경우, 읽지 말아야 할 메모리에 접근하게 됩니다. 즉, i >= m_length 일 때에도 m_data[i] 에 접근하므로 정의되지 않은 동작이 발생하게 됩니다.

 

또한,

void insertBefore(const int& insert, const int& before)
{
    if (before < 0 || before > m_length)
    {
        std::cout << "배열의 크기 확인" << std::endl;
        return;
    }

    int* temp_data = new int[m_length + 1];

    for (int i = 0, j = 0; i < m_length + 1; i++)
    {
        if (i == before)
        {
            temp_data[i] = insert;
        }
        else
        {
            temp_data[i] = m_data[j++];
        }
    }

    delete[] m_data;
    m_data = temp_data;
    m_length++;
}

: 여기에서 temp_data[i] = m_data[j++] 으로 j 값을 매번 증가시키는 경우, 반복문이 끝나기전 jm_length 의 범위를 초과하여 잘못된 메모리에 접근할 수 있습니다.

 

예를 들어,

int main()
{
	IntArray my_arr{ 1, 3, 5, 7, 9 };

	my_arr.insertBefore(10, 1);
	std::cout << my_arr << std::endl;

	my_arr.resize(10);
	std::cout << my_arr << std::endl;

	my_arr.push_back(13);
	std::cout << my_arr << std::endl;
}

질문자님의 코드에서 main() 함수를 위와 같이 바꾸어 메모리 검사를 진행해보면, resize() 함수와 insertBefore() 함수에서 잘못된 메모리 접근이 발생합니다.

image.png

 

만약, 제가 질문자님의 코드를 수정해본다면 resize() 함수의 반복문 안의 부분을

if (i < m_length)
    temp_data[i] = m_data[i];
else
    temp_data[i] = 0; // 초기화

과 같이 변경한 후, insertBefore() 함수에서 수정된resize() 함수를 활용하여 배열의 크기를 조정할 것 같습니다.

 

위 내용 이외에는 문제 없이 잘 구현하셨습니다.
의욕적으로 학습하시는 점 진심으로 응원드리며, 잘 학습하고 계시는 것 같아 한번 더 응원드립니다! 😁

 

아래는 문제가 있거나 부족한 부분이 아닌, 코드를 살펴보면서 추가적으로 개선해보셔도 좋을 것 같은 부분에 대한 피드백입니다.

IntArray(const std::initializer_list<int> number)
{
    m_length = number.size();
    m_data = new int[m_length];

    int count = 0;
    for (auto& arr : number)
    {
        if (count < m_length)
        {
            m_data[count] = arr;
            ++count;
        }
    }
}

: 이 부분에서 if (count < m_length) 조건문은 불필요한 부분 같습니다. for() 문 내부에서 m_length 만큼 반복하기 때문에 countm_length 보다 커지는 경우가 없습니다.

 

IntArray(const IntArray& copy)
{
    m_length = copy.m_length;
    if (m_length > 0)
    {
        m_data = new int[m_length];
        for (int i = 0; i < m_length; i++)
            m_data[i] = copy.m_data[i];
    }
    else
    {
        m_data = nullptr;
    }
    std::cout << "복사 생성자 호출" << std::endl;
}

: 복사 생성자의 경우 복사 대상 배열이 비어있는 경우, 즉, m_length == 0 인 대상 배열의 경우에 대해서 명시적으로 처리하면 더 안전한 코드가 됩니다.

 

잘 작성하셨습니다!

 

IntArray 구현 과제와 관련된 다른 수강생 분들의 질문&답변 사례도 첨부드리오니, 비교해보시면서 학습에 도움이 되시길 바래봅니다.

0

안녕하세요, 인프런 AI 인턴입니다. jjk0806님

IntArray 클래스 구현에 대해 피드백을 요청하셨군요. 여러 가지 작업을 잘 수행하기 위한 기능이 포함되어 있는 것 같습니다. 몇 가지 중요한 점과 개선 사항을 짚어드리겠습니다.

좋은 점:

  1. 복사 생성자: 복사 생성자를 잘 구현해 주셨습니다. 이렇게 함으로써 객체 복사를 할 때 문제가 발생하지 않습니다.
  2. 메모리 관리: 각 함수에서 메모리를 할당 및 해제하는 걸 잊지 않고 잘 처리해 주셨습니다. 특히 소멸자에서 메모리 해제를 수행하고 있고, 이를 통해 메모리 누수를 방지할 수 있습니다.
  3. 각 멤버 함수의 역할이 명확: 각 메소드가 수행해야 할 역할을 잘 구현해주셨습니다. 예를 들어, reset 함수는 배열을 초기 상태로 되돌리기 위해 사용됩니다.

개선 사항:

  1. 예외 처리 강화: resize, insertBefore, remove 함수 모두에서 범위를 벗어난 접근에 대한 예외 처리를 더 강화할 필요가 있습니다. 이러한 처리가 있어야 프로그램이 예기치 않은 입력으로부터 더욱 안전한 동작을 할 수 있습니다.
  2. 복사 생성자 및 복사 연산자 검토: 현재 복사 생성자는 잘 구현되어 있지만, 복사 할당 연산자(assignment operator)를 구현하시면 좋습니다. 이를 통해 확실한 복사 동작이 가능합니다. 두 작업은 함께 구현되어야 복사 생성자와 마찬가지로 잘 동작합니다.
  3. 리사이즈 오류: resize 함수에서는 기존 데이터의 범위를 넘어서는 경우 새 메모리 공간을 0으로 초기화 하고 있습니다. 그러나 복사할 데이터가 그보다 적을 경우 사용되지 않는 메모리는 초기화되지 않기 때문에 이 부분에 대해서도 고려할 필요가 있습니다.

위 내용에 관해 추가로 궁금한 부분이 있다면, 자유롭게 질문 주세요. 다음은 비슷한 질문과 답변 링크를 참조하셔서 더 많은 정보를 얻으실 수 있습니다:

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

jjk0806님의 프로필 이미지
jjk0806

작성한 질문수

질문하기