• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    해결됨

연습문제 질문있습니다.

22.09.27 04:51 작성 조회수 187

0

IntArray& operator = (const std::initializer_list<int>& list)
{
	cout << "Assignment operator " << endl;

	delete[] m_data;

	m_length = list.size();
	m_data = new int[m_length];

	int count = 0;
	for (auto& element : list)
	{
		m_data[count] = element;
		++count;
	}

	return *this;
}

연습문제로 이렇게 짜봤는데 m_data[count] = element; 부분에서 buffer overrun이 발생한다고 나옵니다. 그런데 IntArray(const std::initializer_list<int>& list)를 만들 때도 똑같은 코드가 쓰였는데 이때는 왜 에러메시지가 발생하지 않았는지 궁금합니다.

답변 1

답변을 작성해보세요.

0

강민철님의 프로필

강민철

2022.09.29

혹시 전체 소스 코드를 첨부해주실 수 있을까요?

thd2tn님의 프로필

thd2tn

질문자

2022.09.29

// 기본 자료형으로 array를 만들 때는 initializer_list를 이용해서 값을 편하게 초기화할 수가 있었다.
// 이번에는 class 같은 사용자 정의 자료형에서 생성자나 대입 연산자를 만들 때 편하게 사용할 수 있는 std::initilalizer_list 사용법에 대해서 알아본다.

#include <iostream>
#include <cassert>
#include <initializer_list>
using namespace std;

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

public:
	IntArray(unsigned length)
		: m_length(length)
	{
		m_data = new int[length];
	}

	IntArray(const std::initializer_list<int>& list)
		: IntArray(list.size())
		// 다른 생성자를 호출해서 메모리를 받아오고 있다. IntArray(unsigned length) 생성자에서 메모리를 받아주고 있다.
	{
		int count = 0;
		for (auto& element : list)
		{
			m_data[count] = element;
			++count;

			//m_data[count++] = element;
			// C 스타일에 익숙한 사람들은 안에 넣어버리기도 한다. 
			// 요즘에는 컴파일러도 빨라지고 컴퓨터도 빨라지고 그래서 교수같은 경우는 사람이 실수하지 않도록 분리하는 편이다.
		}

		//for (unsigned count = 0; count < list.size(); ++count)
		//	m_data[count] = list[count]; // error
		// count가 따로 되어있으니깐 번거로워보여서 옛날 프로그래머들은 이렇게 시도할 수 있다.overrun
		// 그런데 std::initializer_list는 대괄호 operator를 제공하지 않는다. std::array나 std::vector에서는 사용할 수 있었는데 std::initializer_list는 제공해주지 않는다.
	}
	// 그래서 내부적으로 구현이되어있을 때 std::initializer_list 같은 경우는 iterator라는 것을 사용해서 for문을 돌리게 되어있는데
	// for-each문은 내부적으로 std::initializer_list 안에 들어있는 iterator를 사용하는 구조이다. 이거는 std 라이브러리를 설명할 때 좀 더 자세하게 설명할 것이다.
	// 편하게 사용하는 것은 좋은데 다른 사람들이 내가 구현할 것을 미리 구현해준 거기 때문에 어떻게 구현되어있나는 추가적으로 공부해야 된다.
	// 어쨌든 공부하는 게 내가 다 구현하는 것보다는 훨씬 편하다. 이거는 뒤에 가서 강의 보면 그냥 이런 거였구나, 이렇게 쓰면 되는구나 하면 되는 거니깐 일단은 이렇게 번거롭더라도 count를 따로 붙여서 구현하는게 더 편하다 정도 생각하면 된다.

	~IntArray()
	{
		delete[] this->m_data;
	}

	//TODO: overload operator =
	// 사실 std::initializer_list을 이용해서 생성자를 구현하면 대입 연산자도 같이 오버로딩해주는게 좋다.

	IntArray& operator = (const std::initializer_list<int>& list)
	{
		cout << "Assignment operator " << endl;

		delete[] m_data;

		m_length = list.size();
		m_data = new int[m_length];

		int count = 0;
		for (auto& element : list)
		{
			m_data[count] = element;
			++count;
		}

		return *this;
	}

	friend ostream& operator << (ostream& out, IntArray& arr)
	{
		for (unsigned i = 0; i < arr.m_length; ++i)
			out << arr.m_data[i] << " ";
		out << endl;

		return out;
	}
};

int main()
{
	int my_arr1[5] = { 1, 2, 3, 4, 5 };
	int* my_arr2 = new int[5]{ 1, 2, 3, 4, 5 };

	auto il = { 10, 20, 30 };
	// #include <initializer_list>를 주석처리하면 에러가 난다.

	//IntArray int_array = { 1, 2, 3, 4, 5 };
	IntArray int_array{ 1, 2, 3, 4, 5 };
	int_array = { 1, 2, 3, 4, 5, 6, 7 };
	cout << int_array << endl;

	return 0;
강민철님의 프로필

강민철

2022.10.02

buffer overrun만이 발생하는 것이 맞나요?

첨부하신 소스코드로는 아래와 같이 다수의 에러가 나오는 것 같아서요.

test.cc:9:20: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions]
        unsigned m_length = 0;
                          ^
test.cc:10:14: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions]
        int* m_data = nullptr;
                    ^
test.cc:19:22: error: no template named 'initializer_list' in namespace 'std'
        IntArray(const std::initializer_list<int>& list)
                       ~~~~~^
test.cc:34:35: error: no template named 'initializer_list' in namespace 'std'
        IntArray& operator = (const std::initializer_list<int>& list)
                                    ~~~~~^
test.cc:23:8: warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
                for (auto& element : list)
                     ^
test.cc:23:22: warning: range-based for loop is a C++11 extension [-Wc++11-extensions]
                for (auto& element : list)
                                   ^
test.cc:44:8: warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
                for (auto& element : list)
                     ^
test.cc:44:22: warning: range-based for loop is a C++11 extension [-Wc++11-extensions]
                for (auto& element : list)
                                   ^
test.cc:66:27: error: expected ';' at end of declaration
        int* my_arr2 = new int[5]{ 1, 2, 3, 4, 5 };
                                 ^
                                 ;
test.cc:68:2: warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
        auto il = { 10, 20, 30 };
        ^
test.cc:68:12: error: cannot deduce type of initializer list because std::initializer_list was not found; include <initializer_list>
        auto il = { 10, 20, 30 };
                  ^
test.cc:72:11: error: no matching constructor for initialization of 'IntArray'
        IntArray int_array{ 1, 2, 3, 4, 5 };
                 ^
test.cc:13:2: note: candidate constructor not viable: requires single argument 'length', but no arguments were provided
        IntArray(unsigned length)
        ^
test.cc:6:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
class IntArray
      ^
test.cc:72:20: error: expected ';' at end of declaration
        IntArray int_array{ 1, 2, 3, 4, 5 };
                          ^
                          ;
test.cc:73:14: error: expected expression
        int_array = { 1, 2, 3, 4, 5, 6, 7 };
                    ^
7 warnings and 7 errors generated.
thd2tn님의 프로필

thd2tn

질문자

2022.10.04

// 기본 자료형으로 array를 만들 때는 initializer_list를 이용해서 값을 편하게 초기화할 수가 있었다.
// 이번에는 class 같은 사용자 정의 자료형에서 생성자나 대입 연산자를 만들 때 편하게 사용할 수 있는 std::initilalizer_list 사용법에 대해서 알아본다.

#include <iostream>
#include <cassert>
#include <initializer_list>
using namespace std;

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

public:
	IntArray(unsigned length)
		: m_length(length)
	{
		m_data = new int[length];
	}

	IntArray(const std::initializer_list<int>& list)
		: IntArray(list.size())
		// 다른 생성자를 호출해서 메모리를 받아오고 있다. IntArray(unsigned length) 생성자에서 메모리를 받아주고 있다.
	{
		int count = 0;
		for (auto& element : list)
		{
			m_data[count] = element;
			++count;

			//m_data[count++] = element;
			// C 스타일에 익숙한 사람들은 안에 넣어버리기도 한다. 
			// 요즘에는 컴파일러도 빨라지고 컴퓨터도 빨라지고 그래서 교수같은 경우는 사람이 실수하지 않도록 분리하는 편이다.
		}

		//for (unsigned count = 0; count < list.size(); ++count)
		//	m_data[count] = list[count]; // error
		// count가 따로 되어있으니깐 번거로워보여서 옛날 프로그래머들은 이렇게 시도할 수 있다.overrun
		// 그런데 std::initializer_list는 대괄호 operator를 제공하지 않는다. std::array나 std::vector에서는 사용할 수 있었는데 std::initializer_list는 제공해주지 않는다.
	}
	// 그래서 내부적으로 구현이되어있을 때 std::initializer_list 같은 경우는 iterator라는 것을 사용해서 for문을 돌리게 되어있는데
	// for-each문은 내부적으로 std::initializer_list 안에 들어있는 iterator를 사용하는 구조이다. 이거는 std 라이브러리를 설명할 때 좀 더 자세하게 설명할 것이다.
	// 편하게 사용하는 것은 좋은데 다른 사람들이 내가 구현할 것을 미리 구현해준 거기 때문에 어떻게 구현되어있나는 추가적으로 공부해야 된다.
	// 어쨌든 공부하는 게 내가 다 구현하는 것보다는 훨씬 편하다. 이거는 뒤에 가서 강의 보면 그냥 이런 거였구나, 이렇게 쓰면 되는구나 하면 되는 거니깐 일단은 이렇게 번거롭더라도 count를 따로 붙여서 구현하는게 더 편하다 정도 생각하면 된다.

	~IntArray()
	{
		delete[] this->m_data;
	}

	//TODO: overload operator =
	// 사실 std::initializer_list을 이용해서 생성자를 구현하면 대입 연산자도 같이 오버로딩해주는게 좋다.

	IntArray& operator = (const std::initializer_list<int>& list)
	{
		cout << "Assignment operator " << endl;

		delete[] m_data;

		m_length = list.size();
		m_data = new int[m_length];

		int count = 0;
		for (auto& element : list)
		{
			m_data[count] = element;
			++count;
		}

		return *this;
	}

	friend ostream& operator << (ostream& out, IntArray& arr)
	{
		for (unsigned i = 0; i < arr.m_length; ++i)
			out << arr.m_data[i] << " ";
		out << endl;

		return out;
	}
};

int main()
{
	int my_arr1[5] = { 1, 2, 3, 4, 5 };
	int* my_arr2 = new int[5]{ 1, 2, 3, 4, 5 };

	auto il = { 10, 20, 30 };
	// #include <initializer_list>를 주석처리하면 에러가 난다.

	//IntArray int_array = { 1, 2, 3, 4, 5 };
	IntArray int_array{ 1, 2, 3, 4, 5 };
	int_array = { 1, 2, 3, 4, 5, 6, 7 };
	cout << int_array << endl;

	return 0;
}


return 0; 밑에 } 하나가 빠져있었네요 죄송합니다...