일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 참조자
- 스마트 포인터
- 상속
- exception
- 예외
- c++
- 비교 함수 객체
- 함수 객체
- Smart Pointer
- virtual function
- effective stl
- 게임
- 메타테이블
- more effective c++
- operator new
- 암시적 변환
- 반복자
- implicit conversion
- 티스토리챌린지
- reference
- 영화 리뷰
- UE4
- lua
- 언리얼
- modern effective c++
- 영화
- 다형성
- Effective c++
- 오블완
- resource management class
Archives
- Today
- Total
스토리텔링 개발자
[Effective STL] 49. 컴파일러 에러 해석하기 본문
728x90
항목 49. STL에 관련된 컴파일러 진단 메시지를 해석하는 능력을 가지자
컴파일러 에러 예시 1
vector<int> v(10); // 크기 10의 벡터를 하나 만든다. 성공.
string s(10); // 크기 10인 string 객체를 만든다? 실패
- 비주얼 c++에서 아래와 같은 에러가 발생한다.
example.cpp(20): error C2664:'__thiscall std::basic_string<char, struct
std::char_traits<char>,class std::allocator<char>
>::std::basic_string<char, struct std::char_traits<char>,class
std::allocator<char> >(const class std::allocator<char> &)': cannot convert
parameter 1 from 'const int' to 'const class std::allocator<char> &'
Reason: cannot convert from 'const int' to 'const class std::allocator<char>'
No constructor could take the source type, or constructor overload
resolution was ambiguous
- string은 클래스가 아니라, 아래 형태로 만든 typedef 타입이다.
basic_string<char, char_traits<char>, allocator<char> >
- C++에서 쓰이는 string처럼 동작하는 모든 객체는 basic_string 템플릿을 인스턴스화한 것이다.
- 그렇기에 에러 메시지에 basic_string이 언급되는 것이다.
- 즉, 위 에러 메시지에서 basic_string 부분은 string으로 치환 가능하다.
example.cpp(20): error C2664:'__thiscall string::string(const class
std::allocator<char> &)': cannot convert parameter 1 from 'const int' to
'const class std::allocator<char> &'
- 할당자를 언급하는 이유?
- 모든 표준 컨테이너엔 할당자를 받아들이는 생성자가 준비되어 있다.
- 컴파일러는 몇 가지 이유 때문에 매개 변수를 하나 넣은 생성자를 무조건 할당자를 받아들이는 할당자로 간주해 버린다.
- 즉, 컴파일러가 착각했고 이 에러 메시지는 틀렸다.
- 할당자를 받는 생성자는 웬만하면 쓰지 말자.
- 이 생성자는 해당 컨테이너와 동일한 타입인데, 동등하지 않은(inequivalent) 할당자를 가진 상태로 빠뜨려 버린다.(항목 11 참조)
컴파일러 에러 예시 2
class NiftyEmailProgram
{
private:
using NicknameMap = map<string, string>;
NicknameMap nicknames; // 닉네임 - email 주소
public:
...
void showEmailAddress(const string& nickname) const;
};
// 구현에서 에러가 발생한다...
void NiftyEmailProgram::showEmailAddress(const string& nickname) const
{
...
NicknameMap::iterator i = nicknames.find(nickname);
if(i != nicknames.end()) ...
...
}
example.cpp(17): error C2440: 'initializing': cannot convert from 'class std::_Tree<class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> >,struct
std::pair<class std::basic_string<char, struct std::char_traits<char>,class
std::allocator<char> > const .class std::basic_string<char, struct
std::char_traits<char>,class std::allocator<char> > >,struct std::map<class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> >.class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> >,struct
std::less<classstd::basic_string<char,structstd::char_traits<char>, class
std::allocator<char> > >,class std::allocator<class std::basic_string<char, struct,
std::char_traits<char>,class std::allocator<char> > > >::_Kfn, struct std::less<class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> > >,class
std::allocator<class std::basic_string<char, struct, std::char_traits<char>,class
std::allocator<char> > > >::const_iterator' to 'class std::_Tree<class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> >,struct
std::pair<class std::basic_string<char, struct std::char_traits<char>,class
std::allocator<char> > const .class std::basic_string<char, struct
std::char_traits<char>,class std::allocator<char> > >,struct std::map<class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> >,class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> >,struct
std::less<classstd::basic_string<char,structstd::char_traits<char> .class
std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> > > >::_Kfn, struct std::less<class
std::basic_string<char, struct std::char_traits<char>,class std::allocator<char> > >,class
std::allocator<class std::basic_string<char, struct std::char_traits<char>,class
std::allocator<char> > > >::iterator'
No constructor could take the source type, or constructor overload resolution was
ambiguous
- 일단 위에서 배운대로 basic_string을 string으로 치환하여 간소화시킨다.
example.cpp(17): error C2440: 'initializing': cannot convert from 'class
std::_Tree<class string, struct std::pair<class string const ,class string
>,struct std::map<class string, class string, struct std::less<class string
>,class std::allocator<class string > >::_Kfn, struct std::less<class string
>,class std::allocator<class string > >::const_iterator' to 'class
std::_Tree<class string, struct std::pair<class string const .class string
>,struct std::map<class string, class string, struct std::less<class string
>,class std::allocator<class string > >::_Kfn,struct std::less<class string
>,class std::allocator<class string > >::iterator'
No constructor could take the source type, or constructor overload
resolution was ambiguous
- std::_Tree
- 밑줄(_)과 대문자는 라이브러리 제작자들에게 예약된 것이다.
- 즉, STL의 컴포넌트를 구현하는 데 사용되는 내부 템플릿이다.
- std::map<class string, class string, struct std::less<class string >, class std::allocator<class string> >
- 우리가 사용한 맵의 정확한 타입이다.
- 이를 우리가 선언한 이름(NickNameMap)으로 바꾸면 또 간소화시킬 수 있다.
example.cpp(17): error C2440: 'initializing': cannot convert from 'class
std::_Tree<class string, struct std::pair<class string const, class string
>,struct NicknameMap::_Kfn, struct std::less<class string >,class
std::allocator<class string > >::const_iterator' to 'class std::_Tree<class
string, struct std::pair<class string const ,class string >,struct
NicknameMap::_Kfn, struct std::less<class string >,class std::allocator<class
string > >::iterator'
No constructor could take the source type, or constructor overload resolution was ambiguous
- 사실 _Tree는 내부 템플릿이므로 에러를 이해하기 위해 굳이 깊게 이해할 필요가 없다.
- SOMETHING으로 치환해 버리자.
example.cpp(17): error C2440: 'initializing': cannot convert from 'class
std::_Tree<SOMETHING>::const_iterator' to 'class
std::_Tree<SOMETHING>::iterator'
No constructor could take the source type, or constructor overload
resolution was ambiguous
- 이해하기 쉬운 코드가 되었다.
- const_iterator를 iterator로 변환하려고 해서 발생한 에러임이 일목요연하다.
- showEmailAddress가 const 멤버 함수이기에 NicknameMap::iterator i = nicknames.find(nickname);의 반복자가 const_iterator가 된 것이었다.
STL 컴파일러 에러 이해하기 팁
- vector와 string의 경우, 반복자는 포인터와 똑같으므로, iterator를 가지고 실수를 했다면 컴파일러 진단 메시지는 포인터 타입을 언급할 가능성이 매우 높다.
- 예를 들어 소스 코드에 vector<double>::iterator가 들어있다면 컴파일러 메시지는 십중팔구 double* 라고 한다.
- back_insert_iterator, front_insert_iterator, insert_iterator 등을 운운하는 메시지는 거의 항상 back_inserter나 front_inserter, inserter를 호출할 때 실수를 저질렀다는 뜻이다.(항목 30 참조)
- binder1st나 binder2nd 등이 언급된다면 bind1st, bind2nd를 잘못 호출했다고 생각하면 된다.
- 출력 반복자(ostream_iterator, ostreambuf_iterator(항목 29 참조), back_inserter, front_inserter, inserter에서 반환된 반복자들)에 대해 실수했을 때는 대입 연산자를 메시지에서 발견할 수 있다.
- 출력 반복자는 대입 연산자(operator=)의 내부에서 출력, 삽입 동작을 하기 때문이다.
- STL 알고리즘의 내부가 잘못되었다는 에러 메시지라면, 그 알고리즘과 함께 사용한 타입에 문제가 있다는 뜻이다.
- 예를 들어 잘못된 반복자를 넘겼다던가 하는 이유일 것이다.
- vector나 string, for_each 와 같이 자주 쓰이는 STL 컴포넌트를 사용하고 있는데 컴파일러 쪽에서 이해를 못하겠다는 에러를 발생시킨다면, #include를 빼먹은 것이다.
- 지금은 되도 다른 플랫폼으로 이식할 때 문제가 발생할 수 있다.(항목 48 참조)
728x90
'개발 > Effective STL' 카테고리의 다른 글
[Effective STL] 50. STL 웹 사이트 (0) | 2025.02.03 |
---|---|
[Effective STL] 48. include (0) | 2025.01.20 |
[Effective STL] 47. 가독성이 떨어지는 코드 자제하기 (0) | 2025.01.17 |
[Effective STL] 46. 함수 vs 함수 객체(람다) (0) | 2025.01.16 |
[Effective STL] 45. 탐색 전략 선택 (0) | 2025.01.15 |
Comments