我想知道如果分配子例程的結果導致複製數據。是否將子例程的結果分配給數據副本?
sub maketext { 'text' };
my $foo = maketext();
my $foo_ref = \$foo;
my $bar_ref = \maketext();
在上述例子中,將在一個不是創建的$bar_ref
更多拷貝的創建的$foo_ref
結果?
我該如何說服自己等同或不等同?
我想知道如果分配子例程的結果導致複製數據。是否將子例程的結果分配給數據副本?
sub maketext { 'text' };
my $foo = maketext();
my $foo_ref = \$foo;
my $bar_ref = \maketext();
在上述例子中,將在一個不是創建的$bar_ref
更多拷貝的創建的$foo_ref
結果?
我該如何說服自己等同或不等同?
的數據複製似乎發生
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;
}
當您指定的這無需額外的數據副本是由一個變量的迴歸,因爲它是返回的參考。
Perl 必須複製的數據。否則,對變量$foo
的任何後續修改都會嘗試修改字符串常量'text'
,這會導致代碼死機。
也就是說在
for ('text') {
$_ = 'test';
}
這引起了該錯誤的只讀值
修改會發生什麼企圖
是的,它的副本。
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
然而,字符串緩衝區不被複制歸功於寫入時複製(COW)功能。事實上,當你做了my $text = 'text';
時,它甚至都沒有被複制過。這意味着常量$text
和$$ref
都是共享相同的字符串緩衝區(直到它們的一個字符串緩衝區被編輯),即使它們是完全不同的標量。
您可以避免使用左值子部分複製返回值。
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
[...]
你的第一句話是「是的,它複製了」,但在閱讀你的答案的COW部分之後,似乎我的問題中的「數據」的定義需要更具體。從這個答案我明白*標量*被複制,但不是底層字符串緩衝區(直到值被修改)。 我注意到左值子,雖然它避免了副本,它會創建一個新的標量每個調用(仍然具有相同的PV),而非左值版本重用相同的變量。 –
'my'變量在可能時確實被重用(在子退出時確定)。如果一個'my'變量是從一個左值子元素返回的,顯然不可能重用它。 – ikegami
請注意,COW是相對較新的,但在此之前還有另一種優化:緩衝區從臨時數據中盜取。這意味着它是一個「臨時」從一個子返回,它的緩衝區將被「偷」而不是被複制。臨時值是一個構造值(例如,從連接,substr等獲得的值)。 – ikegami
即使想的時間在這裏度過的量是一個巨大的錯誤。你應該考慮哪些代碼更具可讀性。如果結果如此之大,那麼複製確實會產生實際影響,您應該返回一個參考。 –
「不成熟的優化是萬惡的根源」。甚至不要考慮這個,這是微不足道的。除非它不是,但爲此您使用代碼分析器。 – Sobrique
這不一定是微觀優化。我不知道答案,我很想知道它是什麼,只是因爲。 – simbabque