views:

83

answers:

4

I have tried to simplify and annotate the code which is giving me a headache below. It demonstrates my problem. Simply put, I have two separate stacks and I am trying to pop from one stack. For some reason, when you pop one of the stacks, it actually seems to pop the other one as well?! Is this by design and if so, why and how should I work around it?

... or am I just being a muppet? (don't answer that one)

Public Class Form1
Public _stackMaster As New Stack
Public _stackCopy As New Stack
Public _strPopped As String

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    _stackMaster.Push("line1")
    _stackMaster.Push("line2")
    _stackMaster.Push("line3")
    MsgBox("Before copying the Master stack to the Copy stack." & vbCrLf & "_stackMaster.Count=" & _stackMaster.Count & vbCrLf & "_stackCopy.Count=" & _stackCopy.Count)
    _stackCopy = _stackMaster
    MsgBox("After copying the Master stack to the Copy stack." & vbCrLf & "_stackMaster.Count=" & _stackMaster.Count & vbCrLf & "_stackCopy.Count=" & _stackCopy.Count)
    _strPopped = _stackCopy.Pop
    MsgBox("After popping a string from the Copy stack." & vbCrLf & "_stackMaster.Count=" & _stackMaster.Count & vbCrLf & "_stackCopy.Count=" & _stackCopy.Count & vbCrLf & "Why do both counts decrease??  Aren't they separate stacks?")
    End
End Sub
End Class
+1  A: 

This is because you are simply assigning the reference to _stackCopy. This line does not copy the stack, it just copies the reference to the actual object:

_stackCopy = _stackMaster

In .NET, you have reference and value types. A value type will be copied if you assign it to another variable. For a reference type, you copy the reference, but you still only have one object.

So yes, the behaviour you are seeing, is by design.

driis
+3  A: 

You've run into the difference between value types and reference types. Stack is a reference type, meaning that assigning _stackCopy to _stackMaster doesn't copy the stack, but only copies a reference to the exact same location in memory.

When you are performing the last Pop, you are only performing it on one stack, but at that point in your code, _stackCopy and _stackMaster point to exactly the same object.

You could get around this by doing (in C#):

object[] values = _stackMaster.ToArray();
for(int i = 0; i < values.Length; i++)
{
   _stackCopy.Push(values[i]);
}
LorenVS
+1 for actually explaining shortly what copying references actually means and for providing a solution.
0xA3
If I could, I'd +1 it but I can't because I'm still noob :( Thx for the bg info, very useful.
ezwi
A: 

I have not used VB.net much, but it appears you are not doing a deep copy, you are only copying by reference. Here's an analogy:

With your first stack, you have a box that contains items. When you are creating your copy, you are not getting another box and putting the same items in, you are instead creating a sign that says "Look at that box" and points to your original copy. Thus, when you take something about of the box, when you follow the sign of course an item will be missing.

Try googling "pass by reference". They are used a lot in Object Oriented Languages.

phantombrain
+4  A: 
_stackCopy = _stackMaster

This line is your culprit. _stackCopy and _stackMaster are each references to stack instances. When you assign one to the other, you are making them each reference the same instance. What you want to do is Clone _stackMaster and assign THAT to _stackCopy.

_stackCopy = _stackMaster.Clone()
Nick Lewis
This is definitely correct. However, does anybody know why? If I have two integers and I use a similar assignment statement, it copies the value, not the reference. Is declaring a stack in vb basically just declaring a pointer?
Chris
.NET has two object types: reference types and value types. Value types are allocated on the stack (and derive from the base class ValueType), whereas reference types are allocated on the heap (and derive from the base class object), with a reference (basically a managed pointer) allocated on the stack. Primitives (Int32, Single, Double, etc.) are value types, and thus assign directly. `Stack` is a reference type, and thus both `Stack` variables are just references.
Nick Lewis