Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with bounds checking a member std::array inside a const function

Tags:

c++

c++11

mingw

I'm getting strange behavior bounds checking a member std::array with mingw (gcc 4.7.0) with the following code

#include <iostream>
#include <array>

class testClass
{
    std::array<int, 2> testArray;

    public:
        testClass();
        void func() const;

};

testClass::testClass() : testArray({{1, 2}})
{
}

void testClass::func() const
{
    for (int i = 0; i < 2; ++i)
        std::cout << testArray.at(i) << '\n' << testArray[i] << '\n';       
}


int main()
{
    testClass test;
    test.func();
}

Output is

0
1
0
2

The error seems to be related to optimization, as it only crops up when compiled with -O, I tried the individual flags enabled by -O but couldn't narrow it down any further. Making the function non-const also fixes the issue. Could this be a bug or am I missing something?

*edit

Narrowed it down, looks like a bug in the const version of .at()

#include <iostream>
#include <array>

int main()
{
    std::array<int, 2> const testArray = {1, 2};

    for (int i = 0; i < 2; ++i)
        std::cout << testArray.at(i) << '\n' << testArray[i] << '\n';       
}

Same output as above compiled with -std=c++11 -O using mingw 4.7.0 on Windows Xp sp3 and Windows 7 sp1.

*edit 2

Same output again

#include <iostream>
#include <array>

int main()
{
    typedef std::array<int, 2> Tarray;
    Tarray test = {1, 2};

    for (int i = 0; i < 2; ++i)
        std::cout << const_cast<Tarray const*>(&test)->at(i) << '\n' << test.at(i) << '\n';     
}
like image 438
user657267 Avatar asked Aug 27 '12 04:08

user657267


1 Answers

This is part of array header

#ifdef __EXCEPTIONS
  constexpr const_reference
  at(size_type __n) const
  {
return __n < _Nm ? 
       _M_instance[__n] : throw out_of_range(__N("array::at"));
  }
#else
  const_reference
  at(size_type __n) const
  {
if (__n >= _Nm)
  std::__throw_out_of_range(__N("array::at"));
return _M_instance[__n];
  }
#endif

Undef __EXCEPTIONS in main file(or change #ifdef to #ifndef in array) leads to correct output. I don't know, this is right solution or not, but it works.

UPD: I change the code in my array's header to

#ifdef __EXCEPTIONS
  constexpr const_reference
  at(size_type __n) const
  {
return __n < _Nm ? 
       _M_instance[__n] : (throw out_of_range(__N("array::at"))),
                          _M_instance[__n];
   /*return __n < _Nm ? 
            _M_instance[__n] : throw out_of_range(__N("array::at"));*/
  }
#else
  const_reference
  at(size_type __n) const
  {
if (__n >= _Nm)
  std::__throw_out_of_range(__N("array::at"));
return _M_instance[__n];
  }
#endif

Now everything is working correctly

like image 187
awesoon Avatar answered Sep 17 '22 04:09

awesoon