2016-12-16 58 views
3

我想知道如果分配子例程的結果導致複製數據。是否將子例程的結果分配給數據副本?

sub maketext { 'text' }; 

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

my $bar_ref = \maketext(); 

在上述例子中,將在一個不是創建的$bar_ref更多拷貝的創建的$foo_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 

然而,字符串緩衝區不被複制歸功於寫入時複製(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 
[...] 
+0

你的第一句話是「是的,它複製了」,但在閱讀你的答案的COW部分之後,似乎我的問題中的「數據」的定義需要更具體。從這個答案我明白*標量*被複制,但不是底層字符串緩衝區(直到值被修改)。 我注意到左值子,雖然它避免了副本,它會創建一個新的標量每個調用(仍然具有相同的PV),而非左值版本重用相同的變量。 –

+0

'my'變量在可能時確實被重用(在子退出時確定)。如果一個'my'變量是從一個左值子元素返回的,顯然不可能重用它。 – ikegami

+0

請注意,COW是相對較新的,但在此之前還有另一種優化:緩衝區從臨時數據中盜取。這意味着它是一個「臨時」從一個子返回,它的緩衝區將被「偷」而不是被複制。臨時值是一個構造值(例如,從連接,substr等獲得的值)。 – ikegami

相關問題