34

Possible Duplicate:
What's the best way to make a deep copy of a data structure in Perl?

I'm apparently misunderstanding something about how hashrefs work in Perl, and am here looking to correct that.

I need to get a copy of a hashref that I can fiddle with without modifying the original. According to my research, copying a hashref is just as simple as using the equals operator:

my $hashref_copy = $hashref;

But as far as I can tell, all that does is make $hashref_copy a pointer to the original object. Consider this toy bit of code:


my $hashref = {data => "fish"};

my $hashref_copy = $hashref;
$hashref_copy->{data} = "chips";

print "$hashref->{data}\n";

If $hashref_copy were really an independent copy, I'd expect this code to print "fish". Instead, it prints "chips".

So either 1) I'm misunderstanding something or 2) Perl is broken. I'm quite certain it isn't #2, in spite of what my ego would have me think.

Where am I going wrong? And what do I need to do to make modifications to $hashref_copy not show up in the original $hashref?

Community
  • 1
  • 1
BlairHippo
  • 9,502
  • 10
  • 54
  • 78
  • See: http://stackoverflow.com/questions/1546322/whats-the-best-way-to-deep-copy-a-hash-of-hashes-in-perl/1546334#1546334 – Joel Aug 16 '11 at 19:10
  • Indeed, assigning one scalar to another does not result in any hash being copied. It just copies the value of the scalar. You are asking how to copy a hash, create a reference to it, and place that reference in a scalar. – ikegami Aug 16 '11 at 19:33
  • 2
    I am not sure if marking this as a duplicate is helpful - the referred question is about most efficient / clean way to make a deep copy. This is a more basic question. – Ross Attrill Aug 27 '13 at 01:17

3 Answers3

76

When you copy a hashref into another scalar, you are copying a reference to the same hash. This is similar to copying one pointer into another, but not changing any of the pointed-to memory.

You can create a shallow copy of a hash easily:

my $copy = { %$source };

The %$source bit in list context will expand to the list of key value pairs. The curly braces (the anonymous hash constructor) then takes that list an creates a new hashref out of it. A shallow copy is fine if your structure is 1-dimensional, or if you do not need to clone any of the contained data structures.

To do a full deep copy, you can use the core module Storable.

use Storable 'dclone';

my $deep_copy = dclone $source;
Eric Strom
  • 39,821
  • 2
  • 80
  • 152
  • 2
    See also [`Clone`](http://search.cpan.org/perldoc?Clone) – Zaid Aug 16 '11 at 19:21
  • Using `Storable qw(clone)` worked fine for me in Perl 5.22 in 64-bit Linux. Using `Clone qw(clone)` causes exactly the same code to crash due to a segfault internal to Perl. Recommend using `Storable`. – code_dredd Jun 08 '16 at 18:57
10

Yes, assignment just copies the reference (like copying a pointer value in other languages). What you're looking for is called a "deep copy".

Storable::dclone seems to be one solution (perldoc Storable for more information).

Clone is another (perldoc clone); thanks to Zaid for mentioning this in a comment.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
4

If it's just a hash and all you're looking for is a copy of it:

my $hashref = {data => "a"};

my %hash_copy = %{$hashref}; # Create a copy of the hash that $hashref points to
my $hashref_copy = \%hash_copy; # Ref to %hash_copy
$hashref_copy->{data} = "b";

print "$hashref->{data}\n"; # Outputs 'a'
print "$hashref_copy->{data}\n"; # Outputs 'b'
Jared Ng
  • 4,891
  • 2
  • 19
  • 18
  • Thank you; this would indeed do the trick. – BlairHippo Aug 16 '11 at 19:14
  • 6
    @BlairHippo: You probably know this, but I'll mention that if some of the hash values are themselves references, this will only copy those references, not what they refer to. Sounds like that's not a problem for you, but keep it in mind. – Keith Thompson Aug 16 '11 at 19:43
  • 1
    @Keith Thompson: Thank you, and right on all counts. :-) I've documented that line of code to indicate that if the hashref in question is ever asked to hold something more interesting than scalars, a deep copy mechanism like Storable::dclone or Clone::clone will be necessary. – BlairHippo Aug 16 '11 at 19:51
  • @BlairHippo: Might be easier to replace the comment with a call to `Storable::dclone` or `Clone::clone`. Just a thought. – Keith Thompson Aug 16 '11 at 21:39