ArrayCopy() глючит на пересекающихся участках

 
ArrayCopy() глючит, когда копируется часть одного и того же массива в него же самого.

Вот пример:

// Сдвигаем данные массива на один элемент вперед
ArrayCopy( data, data, 1, 0, ArraySize( data ) - 1 );

В этом случае копирование будет отработано некорректно - все элементы массива будут заполнены одним значением.

Необходимо доработать ArrayCopy() - при копировании пересекающихся участков копирование должно выполняться в обратном порядке, чтобы уже копируемые элементы не затирали следующие за ними.

 
Я бы поостерегся делать такие эксперименты. Воспользуйся лучше буферным массивом.
 
Сделайте промежуточное копирование в служебный массив.
 
Rosh писал (а):
Сделайте промежуточное копирование в служебный массив.

Пока так и делаю, но это заметно снижает производительность.
 
Если копирование идет слева направо, то нулевой элемент dest пойдет в первый. Дальше первый пойдет во второй, но значение первого уже изменилось.
В результате все заполнится нулевым элементом!
 
alisa писал (а):
Если копирование идет слева направо, то нулевой элемент dest пойдет в первый. Дальше первый пойдет во второй, но значение первого уже изменилось.
В результате все заполнится нулевым элементом!

Об этом я собственно и написал в первом посте. Чтобы этого не происходило, копирование должно в таких случаях идти в обратном порядке. Думаю, что стоит исправить этот глюк.

Еще одна наколка с ArrayCopy(), которая явно неприятна - параметр count лажается на многомерных массивах, т.к. функция всегда интерпретирует его как число элементов одномерного массива. Приходится умножать его руками на соответствующие размерности - это очень неудобно и совершенно не логично.
 
Пример в студию с многомерным массивом! Как ты думаешь, логично ли копировать часть многомерного массива с помощью этой функции, не указывая явно порядок копирования?
 
Mathemat писал (а):
Пример в студию с многомерным массивом! Как ты думаешь, логично ли копировать часть многомерного массива с помощью этой функции, не указывая явно порядок копирования?

Не совсем понял вас.

Пример? Легко:

double A[ 10 ][ 2 ];
 
// Копирование первого элемента массива во второй
ArrayCopy( A, A, 2, 0, 2 );
Кстати, обратите внимание на двойки. Какой смысл при копировании многомерных массивов в ArrayCopy() указывать число всех копируемых элементов, включаю внутренние размерности? Если бы поддерживались срезы (slices), тогда это еще можно было бы понять. Но так как на них нет и намека, то гораздо логичнее было бы оперировать числом элементов в смысле "первой размерности", как это делает ArrayResize().

А теперь пожалуйста ваш пример в студию: как можно явно указать порядок копирования многомерного массива?
 
bstone, когда я говорил о порядке копирования, я не имел в виду число всех копируемых элементов. Мне тоже приходится работать с двумерными массивами и копировать их частично, в том числе и в двумерные тоже. Но я делаю это всегда через служебные массивы, не полагаясь на не известный нам механизм их копирования - и уж во всяком случае не пытаясь изменять исходный массив "на лету" (чрезвычайно ненадежная и непрозрачная операция).

Что касается slices, то это же очень просто реализовать с помощью функции с параметром, передаваемым по ссылке (см. ниже). А после этого "послойно" скопировать исходный массив в новый, а не в себя. Вот это и есть явное указание порядка копирования. Да, будет медленнее, но с точки зрения читаемости кода и его модификации безусловно удобнее. Ну а если так хочется реализовать быстрый алгоритм, тогда остается только писать dll на другом языке типа C++. А вообще, когда я пишу что-то, почти всегда из двух альтернатив - быстрота исполнения или надежность - выбираю вторую.

Вот, скажем, примерная реализация одномерного slice:

// функция выделяет из двумерного массива source срез (одномерный массив dest), 
// фиксируя первый индекс равным idx.

void slice( double source[][], double& dest[], int idx )
{
    int howmany = ArrayRange( source, 1 ); // размер source по второму индексу
    for( int i = 0; i < howmany; i++ )      dest[ i ] = source[ idx ][ i ];
    return;
}
Парамер howmany можно вынести и в параметры функции, если очень хочется скопировать поменьше элементов.
 

и уж во всяком случае не пытаясь изменять исходный массив "на лету" (чрезвычайно ненадежная и непрозрачная операция).

Не согласен. Это абсолютно надежная и прозрачная операция при условии правильной реализации ArrayCopy(). Для этого у процессора даже есть специальный набор инструкций (все операции по копированию/заполнению учатсков памяти поддерживают прямой и обратный порядок). И даже стандартные функции С типа memcpy() учитывают такие нюансы.

Что касается slices, то это же очень просто реализовать с помощью функции с параметром, передаваемым по ссылке (см. ниже).

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

Ну а если так хочется реализовать быстрый алгоритм, тогда остается только писать dll на другом языке типа C++.


Если бы речь шла о некотором сложном алгоритме, то я бы согласился. В данном случае речь идет о банальном копировании элементов массива :)

А вообще, когда я пишу что-то, почти всегда из двух альтернатив - быстрота исполнения или надежность - выбираю вторую.


К сожалению, вторая альтернатива больно бьет по временным затратам на оптимизацию и анализу эффективности МТС на больших периодах истории.
 

В данном случае речь идет о банальном копировании элементов массива :)

Нет, bstone, это не банальное копирование - и Вы это точно должны понимать: сам массив оказывается и источником для копирования, и объектом модификации. Какое ж это копирование?! При таком "копировании" можно было бы не делать детей, а превращаться в них самим...

bstone
, имеем то, что имеем: MQL4 предоставляет все торговые функции плюс джентльменский набор (минимум) нетрейдерских функций, нужных, по мнению разработчиков, для помощи в трейдинге. Пользователи своими собственными силами разрабатывают нужные им библиотеки и выкладывают их в Code Base. Предъявлять к этому языку критерии, соответствующие языку программирования операционных систем, по меньшей мере неразумно.

Язык MQL4 ориентирован явно на специфичную аудиторию - на трейдеров, желающим тем или иным образом механизировать торговлю. Соответственно и акцент в строгости описания языка смещен больше в сторону трейдерских задач, а описание языка не может быть таким же строгим, как это специфицировано в ANSI-стандарте С++. Если Вы привыкли писать на С++, а MQL4 Вас не устраивает - никаких проблем: dll-то можно подключать!
Причина обращения: