스토리텔링 개발자

[Effective STL] 6. 컴파일러의 분석 오류 본문

개발/Effective STL

[Effective STL] 6. 컴파일러의 분석 오류

김디트 2024. 11. 8. 10:46
728x90

항목 6. C++ 컴파일러의 어이없는 분석 결과를 조심하자

 

 

 

파일에 들어있는 int의 list를 복사하려는 예시
ifstream dataFile("ints.dat");

// 잘못 짜여진 코드
list<int> data(istream_iterator<int>(dataFile),
               istream_iterator<int>());
  • 컴파일은 잘 된다. 하지만, 런타임에 아무 일도 하지 않는다.
    • 파일에서 데이터를 전혀 읽지 않으며,
    • 심지어 리스트조차 만들지도 않는다.
  • 사실 위의 코드는 list 객체를 선언하지도 않았고, 생성자를 호출하지도 않았다!

 

 

 

함수 선언문
// 아래는 모두 함수 선언문이다.
int f(double d);
int f(double (d)); // d를 둘러싼 괄호는 무시
int f(double); // 매개변수 이름이 빠진 버전

// 다른 형태의 함수 선언문 세 가지
int g(double (*pf)()); // pf라는 함수 포인터를 매개 변수로 받는다.
int g(double pf()); // pf에 포인터 표시(*)가 빠진 버전(유효한 문법이다.)
int g(double ()); // 매개변수 이름이 빠진 버전
  • 위 두 가지 버전의 괄호 용법을 비교해보면..
    • 매개 변수를 둘러싼 괄호는 무시해도 되는 괄호이다.
    • 그냥 괄호는 함수의 매개 변수 리스트가 있음을 나타내는 것이다.
      • 즉, 함수의 포인터임을 알리는 것이다.

 

 

 

처음 코드를 다시 해석해보자
// 이는 사실, 리스트 객체가 아니라 data라는 이름의 함수를 선언한 것이다.
list<int> data(istream_iterator<int>(dataFile),
               istream_iterator<int>());
               
// 즉, 아래 형태와 동일하다.
list<int> data(istream_iterator<int> dataFile,
               istream_iterator<int> (*noname_param)())
  • 위와 비슷한 실수..
class Widget { ... };
Widget w(); // 함수 w를 선언한 것으로 해석된다..

 

 

 

동작하도록 수정하는 방법
list<int> data((istream_iterator<int>(dataFile)), // 첫 매개변수에 괄호가 추가되었다.
               istream_iterator<int>());
  • 하지만 위 코드도 모든 컴파일러에 통용되는 것은 아니었다..
    • 몇몇 컴파일러는 심지어 맨 처음 코드처럼 틀리게 선언해야 동작했다.
    • 당연히 이는 코드의 이식성을 떨어뜨린다.(컴파일러가 잘못한 것!)
    • 이제는... 웬만한 컴파일러들은 괜찮지 않을까?

 

 

 

더 좋은 방법
  • istream_iterator들을 익명(annoymous) 객체 선언 하지 말고 이름을 만들어준다.
ifstream dataFile("ints.dat");
istream_iterator<int> dataBegin(dataFile);
istream_iterator<int> dataEnd;
list<int> data(dataBegin, dataEnd);
  • 이 방법은 STL 프로그래밍 스타일에 어울리는 방법은 아니지만..
    • 컴파일러와 프로그래머 모두에게 혼란을 주는 코드보다는 낫다.
728x90
Comments