본문 바로가기
컴퓨터/디버깅

l-value specifies const object

by adnoctum 2010. 4. 13.

   L-value는 할당 연산자 = 를 기준으로 왼쪽에 있는 값, 즉  left-hand value 를 의미하는 것으로, C에서 L-value는 특정한 값으로 설정될 수 있는 변수이어야 함을 의미하는 경우가 대부분이다[각주:1]. 즉,

 

a = 3;

 

위와 같은 구문이 있을 때, 우리는 a라는 변수는 값을 변화시킬 수 있는 특성을 갖고 있다는 것을 가정한다. 만약 a 라는 변수가 그 값을 변화시킬 수 없는 변수라면 위와 같은 구문은 에러를 발생시킨다. 제목의


l-value specifies const object

 

에러 역시 이와 같은 경우로, 말 그대로 해석하자면 'l-value는 const 객체로 지정되어 있다', (그런데 넌 지금 뭐를 하려고 하는 거니?') 정도. 즉, 값을 변경할 수 없다고 상수로 선언한 상태에서 값을 변경하려 했기 때문에 생기는 에러인 것이다. 명시적으로 상수로 선언한 변수의 경우 위와 같은 에러가 나면 쉽게 그 원인을 알 수 있겠지만, 상수가 아닌 변수로 선언되어 있더라도 컴파일러는 상수로 접근을 시도하려 하는 경우가 생길 수 있으며 이럴 때 에러가 생길 수 있다. 이런 경우 상수로 선언하지 않았기 때문에 컴파일러의 에러 메세지가 이상하게 보일 수 있으나 찬찬히 살펴 보면 구조적으로 그 변수를 상수로 간주하고 있을 것이다. 아래의 예와 같이.



에러가 난 부분을 보면 다음과 같다.


 

bool CCrestAreaExtractor::operator()(const std::vector<double>& rid, int onset_time, double* feature_value) const

{

    ASSERT( rid.empty() == false );

    ASSERT( onset_time >= 0 );

    ASSERT( feature_value != NULL );

 

    if(rid.empty() == true) return false;

    if(onset_time < 0) return false;

    if(feature_value == NULL) return false;

 

    if(is_valid() == false) return false;

 

    _termination_code = 0; // 여기가 에러난 코드

    double feature = 0;

    if(_crest_type == 0){// 0 : 시간으로 잡음.

        if(get_crest_area_by_time(rid, onset_time, _crest_length, _direction, &feature) == false) return false;

    }

    else if(_crest_type == 1){ // + 1 : percentile 로 crest를 잡음.

        if(get_crest_area_by_percentile(rid, onset_time, _upper_percentile, _direction, &feature) == false) return false;

    }

    else{

        return false;

    }

    *feature_value = feature;

    return true;

}



위에서 에러가 난 부분은 멤버 변수 [_termination_code]를 0 으로 설정하는 부분이다. 약간 혼동될 수 있는 것은 [_termination_code]는 const object로 선언되어 있지 않다는 사실. 그렇다면 컴파일러는 왜 위와 같은 메세지를 표시한 것일까? 다시 한 번 강조하면,

 

 컴파일러 제작자들은 우리보다 훨씬 뛰어나다. 컴파일러 에러/경고 메세지는 충분히 그 의미를 새겨들을만 하며 대부분의 경우 그 메세지는 정확하다.

 

함수의 원형을 보자. operator()는 const 멤버 함수로 되어 있다. class의 멤버 함수가 const 라는 것은, 그 함수는 함수 내부에서 클래스의 그 어떤 변수의 값도 변화시키지 않는다는 것을 의미한다. 그렇게 선언되어 있음에도 불구하고 위에서는 멤버 변수인 [_termination_code]를 변경시키려고 했다. 그래서 위와 같은 에러 메세지가 표시된 것이었다.

 

해결 방법은, 논리 자체를 operator() 내부에서 [_termination_code]를 설정하지 않게끔 클래스를 다시 설계하거나, operator() 를 const로 하지 않는 것이다.






 

  1. C++ 에서는 참조를 함수의 반환값으로 할 수 있고, 그렇게 되면 연산자 = 를 기준으로 left-hand 에 있는 값이 되더라도 값을 할당해 줄 수 있긴 하다, 즉 주소를 갖는 변수가 아닌 (것으로 보이는) 함수에다가도 값을 설정해 주는 것처럼 보이는 경우도 있기는 하다 [본문으로]