1

そのため、最近バグにパッチを当てようとしているときに、仲間のハッカーが、サブルーチン(メソッド)に渡される文字列の値が非常に大きい可能性があるため、経由でアクセスすると$_[1]メモリコピーが回避されると私に言いました。@_しかし、そもそもサブルーチンに渡された値はコピーされたと思いましたか?次の例では、メモリは2回コピーされますか?または、メソッドに渡すときに作成されたコピーについて間違っていますか?

sub foo {
    my $self = shift

    $_[0]    # access $str in @_ directly
    my ( $str ) = @_; # makes another copy of @_
}

sub bar {
    my $self = shift;
    my $str = 'something very large'; 

    $self->foo( $str ); #copies $str to the @_ of foo
}

これが、メソッド自体に渡すときに(参照自体以外の)コピーを回避するスカラー参照によるパスを許可することを作成者に提案した理由です。繰り返しますが、値をサブルーチンに渡すことは、値がコピーされることを意味します@_か?

4

3 に答える 3

7

http://perldoc.perl.org/perlsub.htmlによると(強調は私のものです):

渡された引数はすべて配列に表示され@_ます。したがって、2つの引数を使用して関数を呼び出すと、それらはとに格納され$_[0]ます$_[1]配列@_はローカル配列ですが、その要素は実際のスカラーパラメーターのエイリアスです。特に、要素$_[0]が更新されると、対応する引数が更新されます(または、更新できない場合はエラーが発生します)。引数が関数が呼び出されたときに存在しなかった配列またはハッシュ要素である場合、その要素は、それが変更されたとき(およびその場合)にのみ作成されます。(以前のバージョンのPerlの中には、要素が割り当てられているかどうかに関係なく要素を作成したものがあります。)配列全体に割り当てると、@_そのエイリアシングが削除され、引数は更新されません。

私の読書では、これは、デフォルトでは、へのコピーが発生しないことを示しているようです@_

私は使用される言語が少し鈍いことを認めますが。

于 2012-09-21T18:44:19.660 に答える
5

はい、の要素@_はエイリアス化されています。引数をサブルーチンに渡すコピーは発生しません。

これは、次のような便利で驚くべきことができることを意味します。

sub strip {
    $_[0] =~ s{^\s+}{};
    $_[0] =~ s{\s+$}{};
}

my $var = "   foo   ";
strip($var);
print $var;    # "foo"

離れた場所でのそのような行動は、通常、驚くべき危険です。strip引数を変更するユーザーへの指示はありません。より安全で明白なことは、値を参照として渡すことです。

sub strip {
    my $ref = shift;
    $$ref =~ s{^\s+}{};
    $$ref =~ s{\s+$}{};
}

my $var = "   foo   ";
strip(\$var);
print $var;    # "foo"

これにより、メモリが節約され(参照のみがコピーされます)、サブルーチン内で引数に名前を付けることができます。また、参照を渡す必要があるため、呼び出し元に変数が変更される可能性があることを通知します。

別の方法は、読み取り専用のエイリアスを使用することです。これにより、変数をコピーしないというメモリの最適化が可能になり、変数に名前を付けることができますが、誤って変更することはありません。

これを実現する方法はいくつかありますが、Method::Signaturesを使用すると便利です。

use Method::Signatures;

func no_copy($string is alias is ro) {
    # $string is an alias to $var
    print "$string\n";

    # But it cannot be altered because $string is read-only.
    # This will throw an error.
    $string .= "bar";
}

my $var = "foo";
no_copy($var);
于 2012-09-21T22:51:49.217 に答える
2

それらは同じ変数の2つの異なる名前であるため、コピーは発生しません$_[0]$str

$ perl -E'my $str; sub { say \$str == \$_[0] ?1:0 }->( $str );'
1

でコピーを作成するのは割り当てですmy ( $str ) = @_;

于 2012-09-21T18:52:08.963 に答える