Ошибка сегментации в шаблоне выражения с использованием типа, созданного с помощью ключевого слова auto

Я строю код с шаблонами выражений для вычислительных ядер. У меня очень короткий вопрос: почему GNU G ++ дает ошибку (4.9.1, скомпилированную с -O3) в строке, содержащей += в следующем примере:

// Like this it crashes
auto expression = Ix_h( Ix(u) );
ut += expression;

Но не тогда, когда я набираю эквивалентный код:

// But like this it does not
ut += Ix_h( Ix(u) );

И Clang, и Intel работают нормально.

Я добавил весь код ниже. Извините за длину, это был самый короткий пример, который я мог создать:

struct Grid
{
Grid(const int itot, const int gc) :
itot(itot), gc(gc), istart(gc), iend(itot+gc), icells(itot+2*gc) {}

const int itot;
const int gc;
const int istart;
const int iend;
const int icells;
};

template<int loc, class Inner>
struct Interp
{
Interp(const Inner& inner) : inner_(inner) {}

const Inner& inner_;

inline double operator()(const int i) const
{
return   (-1./16)*(inner_(i + (-2+loc)) + inner_(i + ( 1+loc)))
+ ( 9./16)*(inner_(i + (-1+loc)) + inner_(i + (   loc)));
}
};

template<class Inner>
inline Interp<1, Inner> Ix(const Inner& inner)
{ return Interp<1, Inner>(inner); }

template<class Inner>
inline Interp<0, Inner> Ix_h(const Inner& inner)
{ return Interp<0, Inner>(inner); }

class Field
{
public:
Field(const Grid& grid) :
grid_(grid),
data_(new double[grid_.icells]) {}

inline double operator()(const int i) const
{ return data_[i]; }

inline double& operator()(const int i)
{ return data_[i]; }

template<class T>
inline Field& operator+=(const T& expression)
{
for (int i=grid_.istart; i<grid_.iend; ++i)
(*this)(i) += expression(i);

return *this;
}

private:
const Grid& grid_;
double* data_;
};

int main()
{
Grid grid(256, 4);

Field u (grid);
Field ut(grid);

// Like this it crashes
auto expression = Ix_h( Ix(u) );
ut += expression;

// But like this it does not
ut += Ix_h( Ix(u) );

return 0;
}

3

Решение

auto expression = Ix_h( Ix(u) );

Вот, Ix(u) создает временный объект, связанный со ссылкой на конструктор преобразования Interp<0, Interp<1, Field>>::Interp(Inner const&), Конструктор инициализирует ссылку inner_ к объекту. Теперь у вас есть ссылка на временное значение, которое будет уничтожено в конце полного выражения Ix_h( Ix(u) ),

Причина, по которой это работает, когда вы делаете ut += Ix_h( Ix(u) ) это потому, что ссылка, а также временные умирает в конце выражения. Инициализация expression просто руки от ссылки. Затем с помощью ut += expression использует объект, который с тех пор умер, что является неопределенным поведением.

Решение: сделать inner_ объект, а не ссылка, поэтому происходит копирование:

Inner inner_;
6

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector