해결된 질문
작성
·
291
1
강의내용 9:30에 멤버변수 초기화하는 부분 질문드립니다.
m_i, m_d, m_c는 잘 초기화 되는데 m_arr는 생성자 초기화 방법중 두번째 방법(아래에서 초기화)에서 에러가 뜹니다. 웬만해선 컴파일 에러보고 해결하는데 에러 설명을 봐도 ";가 필요합니다" 라고만 나와서 질문드립니다
class Something
{
int m_arr[5] {1,2,3,4,5};
.... 생략
public:
Something()
: m_arr{1,2,3,4,5} // 가능
{
m_arr{1,2,3,4,5} // 불가능
m_arr[5]{1,2,3,4,5} // 불가능
}
};
답변 3
0
배열이 생성되는 시점에서만 초기화가 가능하다 하셨는데
생성자 내부에선(위의 코드)
Something()
: m_i(1), m_d(3.14), m_c('a'), m_arr{ 1,2,3,4,5 }
이후에
{
m_i = 3;
m_d = 3.16;
m_c = 'c';
m_arr{ 1,2,3,4,5 }; // 에러가 나는 라인
}
밑의 코드는 추가적으로 할당이 일어나서 바뀐다고 들어서 두번 초기화가 된 셈이므로 오류가 난단 말씀이신거같네요
break point 걸어보니 멤버변수를 선언하는 부분에서 초기값을 넣어주는 코드(m_i = 2부분의 m_arr)는 생성자에서 초기화(m_i = 1부분의 m_arr)를 하게되면 실행이 안되니까 두군데에서 선언하는건 문제가 없는데
맨아래 {} 사이(m_i=3 부분의 m_arr)에 선언한건 중복선언이 되어서 오류가 난다는 말씀이신거같네요 감사합니다
0
아니요.. 세미콜론 붙여도 오류가 납니다
분명 에러는 ';'가 필요합니다 라고 나오지만 컴파일러가 이상한곳에 ;을 넣길 원합니다
c++ 19 사용중입니다
컴파일러가 이런식으로 추천 수정을 해주네요
코드 전체 올려보겠습니다
자꾸 header include가 짤리는데 <iostream> 입니다
#include
using namespace std;
class Something
{
private:
int m_i = 2;
double m_d = 3.15;
char m_c = 'b';
int m_arr[5]{ 100,200,300,400,500 };
public:
Something()
: m_i(1), m_d(3.14), m_c('a'), m_arr{ 1,2,3,4,5 }
{
m_i = 3;
m_d = 3.16;
m_c = 'c';
m_arr{ 1,2,3,4,5 }; // 에러가 나는 라인
}
void print()
{
cout << "m_i:" << m_i << " m_d:" << m_d << " m_c:" << m_c << endl;
int i = 0;
for (auto& element : m_arr)
{
cout << " m_arr[" << i++ << "]: " << element << endl;
}
}
};
int main()
{
Something st;
st.print();
return 0;
}
아 제가 미처 생각을 못했었는데
다시 보니 m_arr{ 1,2,3,4,5 }; 이 문장 자체가 문법에 어긋나는 문장이네요!!
{ } 중괄호를 이용한 초기화는 배열을 처음으로 선언할 때에만 사용이 가능해요!!!
처음으로 m_arr 을 선언하는 부분인 int m_arr[5]{ 100,200,300,400,500 }; 에서 { } 중괄호로 원소들 초기화하는건 허용되는 문법이지만
m_arr{ 1,2,3,4,5 };
이렇게 이미 선언된 이후에 존재하는 배열을 중괄호를 사용해서 원소들을 "전부 한번에 수정"하는 문법은 존재하지 않습니다. 중괄호로 모든 원소를 한번에 초기화하는건 선언 및 초기화 멤버 목록에서만 가능하다는 것을 기억해주세요! 즉, 배열이 생성되는 시점에만 가능한 것입니다. 질문자님께서 에러가 나신 장소인 생성자의 중괄호 영역에서는 이미 m_arr 이 생성된 이후이기 때문에 선언과 동시에 초기화가 하는 것이 아닌 기존 원소들을 { } 로 "한번에 전부 수정"하겠다는 시도이기 때문에 허용되지 않습니다.
모든 원소를 수정하기 위해서는 for(int i = 0; i < 5; ++i) m_arr[i] = i + 1; 이렇게 반복문 사용해서 하나하나 초기화하거나 STL 에 있는 fill 함수 사용해서 초기화해야 합니다.
세미콜론이 필요하다고 에러메세지를 낸 이유는 저 문장 자체가 문법에 어긋나기 때문에, 즉 m_arr 와 {1,2,3,4,5} 가 구분되도록 둘 사이에 세미콜론을 넣으라고 에러메세지가 발생한 것 같네요! (m_arr 와 {1,2,3,4,5} 를 합친 연산은 존재하지 않아 컴파일러가 고려할 수 없는 상황)
컴파일러 입장에서는 m_arr{1,2,3,4,5}; 를
m_arr; // 그냥 m_arr 이름만 쓴 문장 후 세미콜론
{ // 그냥 일반 중괄호 블록
1,2,3,4,5; // 쉼표 연산 후 세미콜론
}
; // 빈문장에 세미콜론한 셈
로 쓰는게 맞다고 본거에요. 이렇게 쓰는게 맞는데! 하고 세미콜론 빠뜨렸다고 알려준 것입니다.
m_arr{1,2,3,4,5} 자체가 없는 문법이기 때문에 위와 같이 해석해서 그렇습니다.
0
오류 메세지대로 ; 넣어주셔야해요!
콜론 : 뒤에 작성하는 생성자 초기화 목록 : m_arr{1,2,3,4,5} 은 세미콜론 ; 이 필요하지 않지만
중괄호 { } 부분은 당연히 문장마다 세미콜론 붙여 주셔야 합니다. 중괄호는 생성자 초기화 목록이 아니에요. 일반 다른 함수들의 Body 처럼 이 중괄호 부분은 생성자의 Body 입니다.
그러니 중괄호 안에서 작성하는 코드들은 평소에 코딩하시는 것처럼 ; 세미콜론 다 붙여주셔야 해요. 불가능이라고 적허주신 중괄호 안에 있는 문장들 뒤에 전부 세미콜론 붙여주세요~!
음.. 제가 처음 쓴 댓글을 다시 한번 정독해주세요!!
두 번 초기화가 되기 때문에 오류라는 것이 아닙니다. 중복 선언이라고 언급하셨는데 제가 말씀드린 것과 거리가 멀어보입니다.
중괄호를 통해 모든 원소를 한번에 "초기화" 하는건 선언때 동시에 하는 것을 전제로 하여 문법적으로 지원을 해주는데
선언 때 초기화하는 것이 아닌, 이미 생성되어 존재하는 원소들의 모든 원소를 { } 로 "수정"하려는건 존재하지 않는 문법이기 때문이라고 말씀을 드렸습니다. 생성자의 중괄호 영역으로 들어왔을 땐 이미 m_arr 이 기존에 생성되어진 상태이기에 이때부턴 초기화 개념이 아닌 수정 개념이 됩니다. (이전에 생성자 초기화 목록에서 m_arr 를 생성해놓은 상태니까요) 모든 원소를 수정하는 것은 말씀 드렸듯 반복문이나 혹은 fill 함수를 사용해야 합니다.
중복 선언이어서가 아니라 애초에 없는 문법이기 때문에 에러가 난 것입니다. 그래서 제가 답변에서도 적었듯이 존재하지 않는 문법이어서 컴파일러가 못 알아 들어서 다른 형태로 오해했기 때문에 세미콜론 넣으라고 말했던거구요!
그리고 더 정확한 이해를 돕기 위해 첨언을 하자면 선언은 중복 선언이 아닌 오직 한군데에서만 이루어졌습니다. 클래스 멤버 필드에서요!
생성자 초기화 목록에서 m_arr {1,2,3,4,5} 를 해주는건 선언이 아닌 "정의" 작업입니다.
선언은 이런게 있다! 아직 존재하진 않지만 이런게 있다! 라는거구요. (클래스는 메모리 상에 존재하지 않는 상태죠. 추상적인 설계도일뿐입니다. int m_arr[5]{ 100,200,300,400,500 };은 클래스 시점에선 "선언" 상태입니다. 미래에 이 클래스 타입으로 생성하는 객체는 m_arr 라는 배열을 가져야하고 얘는 { 100,200,300,400,500 } 로 초기화 시켜~ 라고 선언해두는 것입니다.)
정의는 실제로 메모리에 '최초로 할당'하여 실체화 하는 것을 말합니다. { } 중괄호로 모든 원소를 초기화하는건 정의할 때만 가능한 것이구요! 이미 존재하는, 예전에 이미 정의했었던 배열을 { } 중괄호로 한번에 모든 원소를 수정 하려는 행위는 문법적으로 가능하지 않습니다.