Почему grep на моем фрагменте массива вызывает переполнение стека в Perl? - PullRequest
2 голосов
/ 19 февраля 2009

На днях нужно было перебирать подмножество массива за раз. Первоначально я делал это с помощью сплайсинга - в этом случае не было проблем с разрывом массива. Он будет возвращать N элементов за раз, или что-то еще, что осталось в конце списка. Все прошло хорошо.

Тогда оказалось, что мне нужен массив позже. Вместо сращивания я переключился на срезы массива. БУМ! Программа взорвалась, отправив переполнение стека везде. Какие? Зачем? Как? Я поиграл с этим, и нашел пару вариантов, которые будут работать. Вот тестовый скрипт для демонстрации этой проблемы:

use strict;
use warnings;

my @array = qw(a b c d e f g h i j k l m n o p q r s t u v z x c v b a s d f g a s d f a se g);
my $numPerTest = 5;

my $index = 0;
print "Separating out the subset before grepping it, good.\n";
while ($index < @array)
{
   print "Iteration $index\n";
   my @subset =  @array[$index..($index+$numPerTest)];
   @subset = grep { defined $_ } @subset;
   $index += $numPerTest;
}

$index = 0;
print "Making a copy of the array before grepping works.\n";
while ($index < @array)
{
   print "Iteration $index\n";
   my @subset = grep { defined $_ } @{[ @array[$index..($index+$numPerTest)] ]};
   $index += $numPerTest;
}

$index = 0;
print "Grepping the array slice directly, explodey!\n";
while ($index < @array)
{
   print "Iteration $index\n";
   my @subset = grep { defined $_ } @array[$index..($index+$numPerTest)];
   $index += $numPerTest;
}
1005

(Также, если вы этого не видите, у этого есть другой способ объяснить, почему это происходит.)

Ответы [ 2 ]

9 голосов
/ 19 февраля 2009

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

В первых двух примерах вы использовали его только в качестве значения, поэтому дополнительные элементы не создаются. В третьем это lvalue, и, таким образом, элементы создаются так, что $_ может быть назначено.

Это не поведение, специфичное для срезов: при обычном доступе к массиву поведение точно такое же

6 голосов
/ 19 февраля 2009

Я думаю, что этот кусок кода

@array[$index..($index+$numPerTest)]

создает пустые элементы в вашем массиве. Затем, когда вы тестируете

$index < @array

ваш @array только что стал больше, и ваш индекс никогда не будет больше вашего @array размера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...