Использование each() в хэше после вставки без сброса итератора хеширования приводит к неопределенному поведению, интерпретатор Perl: 0x13932010 в /srv/data203806/MUXmh-Migration/Newperl/localperl/lib/site_perl/5.18.1/x86_64-linux-thread-multi/forks.pm строке 1736.

Все в моем коде работает нормально, но я получаю эту ошибку. Как я могу подавить это предупреждение?

5
Naghaveer R 28 Мар 2014 в 14:31
2
Предупреждение говорит о том, что вы делаете что-то, что вам не разрешено. Это не ложное предупреждение; вы должны решить проблему, а не отключать предупреждение.
 – 
ikegami
28 Мар 2014 в 18:42

3 ответа

Лучший ответ

Это предупреждает:

use strict;
use warnings;
use Data::Dumper;

my %h = (a=>1);
while (my ($k,$v) = each %h) {
   $h{b} = 2;
}

print Dumper \%h;

Это заглушает предупреждение:

use strict;
use warnings;
use Data::Dumper;

my %h = (a=>1);
{
   no warnings qw(internal);
   while (my ($k,$v) = each %h) {
      $h{b} = 2;
   }
}

print Dumper \%h;

Обратите внимание, что категория предупреждений для отключения звука называется internal. Откуда я это узнал? Есть ли у меня какая-то потрясающая память для категорий предупреждений Perl? Нет. Все сообщения об ошибках и предупреждениях Perl хорошо документированы в perldiag; для каждого предупреждения указывается категория, к которой оно принадлежит.

Тем не менее, это предупреждение говорит вам о реальной проблеме. Поведение вашего кода не определено; если вы переключитесь на другую версию Perl, он может внезапно начать работать по-другому. Лучше, чем отключать предупреждение, исправить ваш код!

В моем примере выше быстрым решением было бы использовать each для циклического перебора копии %h, а не самого %h.

use strict;
use warnings;
use Data::Dumper;

my %h = (a=>1);
{
   my %tmp = %h;
   while (my ($k,$v) = each %tmp) {
      $h{b} = 2;
   }
}

print Dumper \%h;
12
tobyink 28 Мар 2014 в 14:54

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

Итак, последовательность такова: - Некоторая случайная пара возвращается из набора ключ / значение, а затем перемещается в ожидаемой форме. (меня это устраивает, я не добавляю кучу всякой всячины) - Сброс для запуска. очевидно, что этого не происходит, иначе в документации сказано. (Я не поддерживаю это действие) - each () возвращает набор (undef, undef) и после этого работает должным образом. Не мой первый выбор, но хорошо, если это одна из неопределенных возможностей. - теряет рассудок; Я бы использовал здесь красочную метафору, но в основном теряю всякий контроль, и Perl ломается сам. Насколько я могу судить, этого не происходит.

Как предложили другие участники, лучше всего кодировать так, чтобы предупреждение не создавалось; однако я привел один пример (простой итератор), где я нажимаю на каждую с высокой частотой (выше), а вставляю и удаляю элементы с меньшей частотой. Я считаю, что поведение Perl без предупреждения вполне подходит.

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

2
ancient.wizard 28 Апр 2017 в 19:52

Следующая техника, которая минимально изменяет существующий код, подавляет предупреждение, избегая опасной операции:

foreach my $key (keys %hash) {
    my $value = $hash{$key};
    # ...
}

Назначение $ value гарантирует, что вам не нужно переделывать код, который следует в содержащем блоке.

0
Art Sackett 9 Авг 2015 в 01:56