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

stl_algo.h:2280: error: assignment of read-only location

by adnoctum 2010. 5. 18.
다음과 같은 에러가 났다.

환경: GCC 4.1.2 20080704 (Red Hat 4.1.2-46) on CentOS 5.4

/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h: In function ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double, std::allocator<double> > >]’:
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2359:   instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double, std::allocator<double> > >]’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2714:   instantiated from ‘void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double, std::allocator<double> > >]’
NR_stat.cpp:188:   instantiated from here
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2280: error: assignment of read-only location

사실 전체 에러 메세지는 훨씬 길다.


무지 복잡해 보이는데, 차근차근 살펴 보면


/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h: In function ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double, std::allocator<double> > >]’:
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2359:   instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double, std::allocator<double> > >]’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2714:   instantiated from ‘void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double, std::allocator<double> > >]’
NR_stat.cpp:188:   instantiated from here
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2280: error: assignment of read-only location

컴파일러 에러 메세지를 토대로 함수의 호출 순서를 파일 이름:Line number 형태로 추정해 보자면,

NR_stat.cpp:188 --> stl_algo.h:2714 --> stl_algo.h:2359

정도가 될 것이고, 이것들은 stl_algo.h의 함수 void std::__insertion_sort 의 안에서 호출된 것일 것이다. 실제로 에러가 난 부분은 발췌된 에러 메세지의 가장 마지막 부분으로 stl_algo.h 파일의 2280 번째 줄에서 read-only 위치에 값을 할당하려고 했다는 것이다. stl_algo.h 파일의 2280 번 근처의 소스 코드를 보면,

 2260 /**

 2261 *  @if maint

 2262 *  This is a helper function for the sort routine.

 2263 *  @endif

 2264 */

 2265 template<typename _RandomAccessIterator>

 2266 void

 2267 __insertion_sort(_RandomAccessIterator __first,

 2268                  _RandomAccessIterator __last)

 2269 {

 2270   if (__first == __last)

 2271     return;

 2272 

 2273   for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)

 2274     {

 2275       typename iterator_traits<_RandomAccessIterator>::value_type

 2276         __val = *__i;

 2277       if (__val < *__first)

 2278         {

 2279           std::copy_backward(__first, __i, __i + 1);

 2280           *__first = __val;

 2281         }

 2282       else

 2283         std::__unguarded_linear_insert(__i, __val);

 2284     }

 2285 }


에러가 난 위치는 random access iterator에다가 값을 할당하고 있는 코드이다. 에러 메세지의 내용이 read-only 위치에 값을 할당하려고 했으므로 아마도 [__first]가 read-only 였을 것이다. 왜 그랬을까? 이것은 즉 [__first]가 const 로 넘어갔다는 의미이다. 실제로 NR_stat.cpp 파일의 188 번째 줄 근처를 보면,

  

  176 bool kstwo(const std::vector<double>& data1, const std::vector<double>& data2, double *d, double *prob)

  177 {

  178         int j1 = 0; int j2 = 0;

  179         int n1 = (int)(data1.size());

  180         int n2 = (int)(data2.size());

  181         double d1 = 0; double d2 = 0;

  182         double dt = 0; double en = 0;

  183         double en1 = 0; double en2 = 0;

  184         double fn1 = 0; double fn2 = 0;

  185 

  186         KSdist ks;

  187 

  188         std::sort(data1.begin(), data1.end());

  189         std::sort(data2.begin(), data2.end());

  190 

  191         en1 = n1; en2 = n2;


std::sort 로 넘기는 [data1]이 const 로 넘어 왔음을 176 번째 줄에서 볼 수 있다. 이렇게 const 로 넘어 온 데이터를, const이면 동작을 진행할 수 없는 std::sort 함수로 넘겼기 때문에 에러가 발생한 것이다.

해결책은 간단하다. 값을 const가 아닌 형태의 call-by-reference나 call-by-value로 받는 것이다. 간단히는 함수의 prototype 에서 const 예약어를 제외하면 되겠지.

STL의 vector는 random access iterator를 제공한다. STL의 sort는 random access iterator를 입력으로 받아들인다. 따라서 위의 경우 iteartor type은 일치를 한다. 그러나 const 지정자가 주어지면서 read-only 형태로 되었기 때문에 sort에서 에러가 난 것이다. vector와는 달리 STL의 set 은 random access iterator 를 제공하지 않기 때문에 sort를 할 수 없다, set을 sort하는 것은 별로 의미도 없고, 일반적으로 sort가 되어 있는 형태로 유지되긴 하지만(하지만 보장할 수는 없겠지, 표준에 그렇게 하라고 되어 있지 않으니).


에러 메세지가 무지 길다고 미리 겁먹지 말자. 차근차근 따져 보면 무지 간단한 경우가 많고, 에러 메세지가 길다는 것은 에러의 원인을 찾아낼 수 있는 힌트가 그만큼 많다는 의미이다.