В чем разница valarray в gcc и msvc (или Linux и Windows)

Я испытываю различное поведение valarray в Windows и Linux. Кто-нибудь знает об этом или знает, где посмотреть? Очевидно, что одна версия, работающая на обеих системах, является правильным C++, но почему другая работает в Windows? Есть ли еще отличия в реализации valarray?

Пример кода, работающего в MSVC/Windows, но не в gcc/Linux:

    valarray<signed short> myValues;
    for(size_t s = 0; s < 10; s++)
    {
        slice dataSlice(1, 1, 1);
        // on Linux, this slice operation gives me a segmentation fault
        myValues= RawData[dataSlice];
    }

Я отследил его, чтобы исправить такой код для версии gcc/Linux:

    for(size_t s = 0; s < 10; s++)
    {
        slice dataSlice(1, 1, 1);
        valarray<signed short> myValues = RawData[dataSlice];
    }

Версии gcc/Linux предполагают, что значение l (myValues) уже инициализировано. В MSVC/Windows в этом нет необходимости. Я могу позвонить myValues.resize(1) в Linux, и это тоже работает.

Теперь, кто-нибудь точно знает о различиях или ресурсе в Интернете? Существуют ли лучшие практики работы с valarray?

Версии программного обеспечения:

  • Windows 7, MS Visual Studio 2010 SP1, компилятор Visual C++ 16.00.40219.01 для 80x86
  • Lubuntu 14.04 64 бит на виртуальной машине, GNU Make 3.81, GCC 4.8.2

Всем спасибо.


Обновление: подробный пример кода. Компилируется. Первый пример дает ошибку сегментации в Linux, но хорошо работает в Windows.

// This example compiles both on Windows with MSVC and on Linux with GCC.
// It gives a segmentation fault in Linux.
// It gives the expected output on Windows.

#include "stdafx.h"

#include <iostream>
#include <valarray>

int main(int argc, char **argv) {

  //init base data

  std::valarray<signed short> myData(10);
  for (int i = 0; i < 10; i++)
  {
    myData[i] = i;
  }

  std::valarray<signed short> myValues;

  for (int i = 0; i < 10; i++)
  {
    myValues = myData[std::slice(0, i, 1)];
    std::cout << "myValues: ";

    for (size_t k = 0; k < myValues.size(); k++)
    {  
        std::cout << myValues[k] << ",";
    }

    std::cout << std::endl;
  }
}

Следующий пример хорошо работает в Linux и Windows. Обратите внимание на объявление и, следовательно, инициализацию myValues ​​внутри цикла for, прямо там, где выполняется нарезка.

#include "stdafx.h"

#include <iostream>
#include <valarray>

int main(int argc, char **argv) {

  //init base data

  std::valarray<signed short> myData(10);
  for (int i = 0; i < 10; i++)
  {
    myData[i] = i;
  }

  for (int i = 0; i < 10; i++)
  {
    std::valarray<signed short> myValues = myData[std::slice(0, i, 1)];
    std::cout << "myValues: ";

    for (size_t k = 0; k < myValues.size(); k++)
    {  
        std::cout << myValues[k] << ",";
    }

    std::cout << std::endl;
  }
}

Ожидаемый результат:

myValues:
myValues: 0,
myValues: 0,1,
myValues: 0,1,2,
myValues: 0,1,2,3,
myValues: 0,1,2,3,4,
myValues: 0,1,2,3,4,5,
myValues: 0,1,2,3,4,5,6,
myValues: 0,1,2,3,4,5,6,7,
myValues: 0,1,2,3,4,5,6,7,8,

person this.myself    schedule 12.11.2014    source источник
comment
Можете ли вы сделать полный пример, который можно скомпилировать? А также, какую версию g++ вы используете?   -  person Mats Petersson    schedule 12.11.2014
comment
@MatsPetersson готово, спасибо за комментарий.   -  person this.myself    schedule 12.11.2014


Ответы (1)


valarray.assign/8:

valarray<T>& operator=(const slice_array<T>&);
valarray<T>& operator=(const gslice_array<T>&);
valarray<T>& operator=(const mask_array<T>&);
valarray<T>& operator=(const indirect_array<T>&);

Требования: длина массива, на который ссылается аргумент, равна size().

Вы создаете myValues как пустой valarray размера 0. Предварительное условие для использования valarray<T>& operator=(const slice_array<T>&); не выполнено.

Заменять

myValues = myData[std::slice(0, i, 1)];

с участием

auto s = std::slice(0, i, 1);
myValues.resize(s.size());
myValues = myData[s];

or

myValues = std::valarray<signed short>(myData[std::slice(0, i, 1)]);

и это будет работать.

Чего я пока не понимаю, так это почему выбрано slice_array<T> operator[](slice slicearr) вместо valarray<T> operator[](slice slicearr) const.

person Paul    schedule 12.11.2014
comment
Да, я тоже видел этот фрагмент документации. И мне ясно, почему это не сработало. Но у меня вопрос: почему поведение Windows отличается от Linux и в чем другие различия между системами? - person this.myself; 12.11.2014
comment
Реализация стандартной библиотеки Microsoft изменяет размер массива в valarray<T>& operator=(const slice_array<T>&);, что не требуется по стандарту. Странно, что myValues.resize(1) помогает во всех случаях, я предполагаю, что это не сработает и для массивов большего размера. - person Paul; 12.11.2014
comment
Это кажется очевидным. Что вы имеете в виду, почему выбрано slice_array<T> operator[](slice slicearr) вместо valarray<T> operator[](slice slicearr) const? - person this.myself; 12.11.2014
comment
valarray<T>::operator[] вызывается в выражении myData[std::slice(0, i, 1)]. Есть две перегрузки: const одна возвращает valarray, а неконстантная возвращает slice_array. Если бы был выбран первый, вам не пришлось бы изменять размер пункта назначения valarray перед назначением. - person Paul; 12.11.2014
comment
Я использую valarray, потому что slice_array является только промежуточным типом, и я думаю, что чище не создавать ссылки на промежуточные типы. Я не знаю, действительно ли это имеет значение. - person this.myself; 12.11.2014
comment
Я говорил о разрешении перегрузки во время компиляции. Почему компилятор выбирает конкретную версию перегруженного operator[]. - person Paul; 12.11.2014