2016-12-16 4 views
3

Я пытаюсь понять, приводит ли при назначении результат подпрограммы к копированию этих данных.Присвоение результата подпрограммы приводит к копированию данных?

sub maketext { 'text' }; 

my $foo = maketext(); 
my $foo_ref = \$foo; 

my $bar_ref = \maketext(); 

В приведенном выше примере, будет создание $foo_ref результате более одной копии, чем создание $bar_ref?

Как я могу убедить себя в их эквивалентности или неравноправии?

+0

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

+1

«Преждевременная оптимизация - это корень всего зла». Даже не думайте об этом, это тривиально. За исключением случаев, когда это не так, но для этого вы используете профилировщик кода. – Sobrique

+3

Это не обязательно микро-оптимизация. Я не знаю ответа, и мне любопытно узнать, что это такое, только потому, что. – simbabque

ответ

4

Данные копирования, как представляется, произойдет

sub maketext { 
    my $text = 'text'; 
    say \$text; 
    return $text; 
} 

my $bar_ref = \maketext(); 
say $bar_ref; 

Печатается

 
SCALAR(0x11f5818) 
SCALAR(0x11cfa68) 

Адреса данных, созданных в суб и что $bar_ref указывает не то же самое.

На лицевой стороне, так как функция возвращает данные, необходимо скопировать их, а также ссылку на это.

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

Вы создаете анонимную скалярную ссылку, но не возвращаете функцию.


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

my $scalar_ref = \do { my $var }; 

или do { \my $var }, или в вашем случае с суб

sub anon_scalar_ref { 
    # ... 
    return \my $var; 
} 

Однако, Я не понимаю, что вы будете использовать. Может быть, вы хотите сделать

sub maketext { 
    # ... define $text ... 
    return \$text; 
} 

При назначении возвращения этого к переменной никакие дополнительные копии данных не производятся, так как это ссылка, которая возвращается.

1

Perl необходимо скопировать данные. В противном случае любая последующая модификация переменной $foo будет попыткой изменить строковую константу 'text', что приведет к смерти вашего кода.

То, что происходит в

for ('text') { 
    $_ = 'test'; 
} 

который поднимает ошибку

модификация только для чтения значения попытка

3

Да, он копирует.

use Devel::Peek qw(Dump); 

sub maketext { 
    my $text = 'text'; 
    Dump($text); 
    return $text; 
} 

my $ref = \maketext(); 
Dump($$ref); 

Выход:

SV = PV(0x8b18a0) at 0x8dbe38 <-- $text is at 0x8dbe38 
    REFCNT = 1 
    FLAGS = (POK,IsCOW,pPOK) 
    PV = 0x8d9f70 "text"\0  <-- String buffer at 0x8d9f70 
    CUR = 4 
    LEN = 10 
    COW_REFCNT = 1 
SV = PV(0x8b1920) at 0x8b0cc8 <-- $$ref is at 0x8b0cc8 
    REFCNT = 1 
    FLAGS = (POK,IsCOW,pPOK) 
    PV = 0x8d9f70 "text"\0  <-- String buffer at 0x8d9f70 
    CUR = 4 
    LEN = 10 
    COW_REFCNT = 1 

Однако строка буфера не скопированные благодаря (КПС) функции копирования при записи. Фактически, он не был даже скопирован, когда вы сделали my $text = 'text'; по той же причине. Это означает, что константа, $text и $$ref все имеют один и тот же строковый буфер (до тех пор, пока не будет отредактирован один из их строковых буферов), хотя они являются совершенно разными скалярами.

Вы можете уйти от того, чтобы возвращаемое значение было скопировано с использованием lvalue sub.

use Devel::Peek qw(Dump); 

sub maketext :lvalue { 
    my $text = 'text'; 
    Dump($text); 
    return $text; 
} 

my $ref = \maketext(); 
Dump($$ref); 

Выход:

SV = PV(0xe43c80) at 0xe6e238 
[...] 
SV = PV(0xe43c80) at 0xe6e238 
[...] 
+0

Ваше первое предложение: «Да, оно копирует», но после прочтения части ответа COW, похоже, определение «данные» в моем вопросе должно быть более конкретным. Из этого ответа я понимаю, что скаляр * скопирован, но не основной буфер строки (пока значение не будет изменено). Я замечаю из подлога lvalue, что, хотя он избегает копирования, он создаст новый скаляр каждого вызова (все еще с тем же PV), тогда как версия, отличная от lvalue, повторно использует одну и ту же переменную. –

+0

Переменные 'my' действительно используются повторно (если они определены в момент выхода sub). Если переменная 'my' возвращается из подмножества lvalue, ее невозможно повторно использовать повторно. – ikegami

+0

Обратите внимание, что COW относительно нова, но перед этим была еще одна оптимизация: кражи буфера из temps. Это означает, что «временный» возвращается из суб, его буфер будет «украден», а не скопирован. Временным является построенное значение (например, полученное из конкатенации, substr и т. Д.). – ikegami

 Смежные вопросы

  • Нет связанных вопросов^_^