On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 28.07.12 19:59. Заголовок: MS VC++ 2010: Самый необычный баг компилятора


Пожалуй описанный далее баг компилятора MS VC++ 2010 является самым необычным и неожиданным. Он никак не связан с какой-нибудь запутанной семантикой языка С++, и проявляется там, где меньше всего его ждешь.

Обнаружил я его совершенно случайно, отвечая на один вопрос на форуме по С++. Имеется класс

class Array 
{
public:
enum { N = 5 };
Array( int value = 0 )
{
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
a[ i ][ j ] = value;
}
}
}

private:
int a[N][N];
};


Спрашивается: как перегрузить для него оператор индексирования, чтобы можно было обращаться к отдельным элементам массива, являющегося членом класса. То есть если в программе объявлен объект данного типа, то хотелось бы иметь привычный синтаксис обращения к элементам этого объекта, что-то вроде:

Array a; 

for ( size_t i = 0; i < Array::N; i++ )
{
std::for_each( a[ i ], a[ i ] + Array::N, [] ( int x ) { std::cout << x << ' '; } );
std::cout << std::endl;
}


Напрашивается решение перегрузить оператор [] для этого класса, который будет возвращать ссылку на заданную строку массива. И я предложил такое решение

#include "stdafx.h" 
#include <algorithm>
#include <numeric>
#include <iostream>

class Array
{
public:
enum { N = 5 };
Array( int value = 0 )
{
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
a[ i ][ j ] = value;
}
}
}

int ( & operator []( size_t i ) )[N]
{
return ( a[ i ] );
}

private:
int a[N][N];
};


int _tmain(int argc, _TCHAR* argv[])
{
Array a;
std::iota( a[1], a[1] + Array::N, 1 );

for ( size_t i = 0; i < Array::N; i++ )
{
std::for_each( a[ i ], a[ i ] + Array::N, [] ( int x ) { std::cout << x << ' '; } );
std::cout << std::endl;
}

return 0;
}


В этом примере создается объект класса Array с именем a, у которого все эелменты массива заполняются по умолчанию нулями. Затем с помощью алгоритма std::iota заполняется вторая сттрока (с индексом 1) массива возрастающими значениями, начиная с 1, чтобы проверить работу предложенного перегруженного оператора индексирования. Ну, а после, сам массив объекта выводится на консоль.

К моему удивлению компилятор выдал следующие сообщения об ошибках:


 цитата:
error C2061: синтаксическая ошибка: идентификатор "size_t"
error C2805: бинарный "operator [" имеет слишком мало параметров
error C2333: Array::operator []: ошибка в объявлении функции; пропуск основного текста функции
error C2676: бинарный "[": "Array" не определяет этот оператор или преобразование к типу приемлемо к встроенному оператору
error C2676: бинарный "[": "Array" не определяет этот оператор или преобразование к типу приемлемо к встроенному оператору
error C2676: бинарный "[": "Array" не определяет этот оператор или преобразование к типу приемлемо к встроенному оператору
error C2676: бинарный "[": "Array" не определяет этот оператор или преобразование к типу приемлемо к встроенному оператору



Здесь важны первые два сообщения об ошибке, потому что остальные сообщения являются лишь следствием этих двух сообщений:


 цитата:
error C2061: синтаксическая ошибка: идентификатор "size_t"
error C2805: бинарный "operator [" имеет слишком мало параметров



Эти сообщения об ошибках довольно странные. С чего это, вдруг, компилятор жалуется на идентификатор size_t?!

Я сначала подумал, что может быть надо указать тип параметра с префиксом пространства имен, то есть в виде: std::size_t. Но ничего не изменилось. По-прежнему выдавались ошибки компиляции. Тогда я подключил заголовок, где явно объявлен тип size_t, а именно <cstdlib>. Но и это не помогло.
Естественно пришла идея проверить код с помощью другого компилятора. Как и следовало ожидать, компилятор GCC 4.7 скомпилировал код без ошибок.
Но затем мне пришла мысль: если компилятор ругается на size_t, то что если заменить size_t на int? Я так и сделал, то есть определение перегруженного оператора записал следующим образом:

int ( & operator []( int i ) )[N] 
{
return ( a[ i ] );
}


По сравнению с исходным оператором здесь изменен только тип единственного параметра. И неожиданно, как по мановению волшебной палочки, код скомпилировался и выполнился!

То есть компилятор MS VC++ 2010 категорически не принимал в качестве типа параметра только тип siize_t, что, естественно, очень странно и ничем не обосновано. Исходный код с size_t совершенно корректный и должен был компилироваться.

Это очень необычный и неожиданный баг компилятора MS VC++ 2010.

Естественно я отослал в Майкрософт сообщение об этом странном баге.

Понять самостоятельно, почему компилятор не воспринимает тип size_t для параметра именно этой оператор-функции, невозможно. Никаких зацепок нет.

Спасибо: 0 
ПрофильЦитата Ответить
Новых ответов нет [см. все]





ссылка на сообщение  Отправлено: 28.07.12 20:00. Заголовок: Пришел ответ от Майк..


Пришел ответ от Майкрософт, в котором они подтвердили о наличии бага:


 цитата:
Posted by Microsoft on 15.05.2012 at 15:37

Hello,

Thank you for reporting. We will consider fixing this in a future release. For some reason typedef being used in the operator signature is causing the error. In the meantime, can you please accept this workaround?

int a[N][N];
typedef int (&array_ref)[N];
array_ref operator []( std::size_t i )
{
return ( a[ i ] );
}

Thanks,
Ulzii Luvsanbat
Visual C++ Team




Я проверил предложенный ими обходной вариант. Действительно, если задать typedef вида

typedef int ( &array_ref )[N];

и переписать оператор-функцию с использованием этого определения,

array_ref operator []( std::size_t i ) 
{
return ( a[ i ] );
}


то код будет успешно компилироваться.

Очень необычный баг!

Спасибо: 0 
ПрофильЦитата Ответить
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 3
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет