Jump to content
Xtreme .Net Talk

Recommended Posts

  • *Experts*
Posted

To really understand what happens, you have to know how memory is used (including pointers and the actual data structures they point to). For most people, that's WAY too much knowledge and just hearing that all non-primitive types are passed byref is good enough. It only comes to byte :) you later, when something isn't quite working as expected and you can't quite figure it out.

 

As long as you understand what's happening and can accurately predict what's going to happen when you call a function, you can call it By Val, By Ref, or Sally Sue Sea Shells. :)

 

-Nerseus

"I want to stand as close to the edge as I can without going over. Out on the edge you see all the kinds of things you can't see from the center." - Kurt Vonnegut
Posted

While it's true you can change the contents of a class when passed to a function, you can't change the original pointer to the class inside of the function.

 

You can actually change the original pointer to the class inside the function if ByRef in VB.NET or ref in C# was used to define the parameter in the method signature. This is what my original code in an earlier post in this thread was supposed to demonstrate.

  • Leaders
Posted
Everything is passed byval by default, even objects. When you pass an object though, you are actually passing a pointer to that object. You can pass the pointer byref or byval. Either way, it will point to the same object so that it is almost like you are passing byref either way. With byval, though, you cant change what the variable points to because you would just be changing a copy of the pointer, not the origional. If you pass by ref, you can change what the variable points to because your dealing with the origional pointer, not a copy of it. There is a difference between passing objects byref and byval, and byval is the default.
[sIGPIC]e[/sIGPIC]
Posted

In C#, everything is passed by value, unless either ref or out is specified on the parameter. For example, an int/Int32 is passed by value; a TrackBar reference is also passed by value. Read that last sentence again: the reference itself is passed by value! Think about the following method:

 

void f(TrackBar tb) { ... }

 

The parameter tb is passed by value. You can see this, as there is absolutely no way for tb to be altered on return to the caller: tb will definitely be referencing the same object (or be null) both before and after the call to f(). Of course, the object to which tb refers can be modified in any way you like. This does not mean that the tb reference itself is being passed by reference! Compare this to the following:

 

void f(ref TrackBar tb) { ... }

 

Now it is possible that tb could be altered, in the eyes of the caller, during the call to f(). That is, tb is being passed by reference. For example, tb could be referring to a TrackBar instance before the call to f(), but be null by the time the method returns.

 

The moral of the story is this: everything (in C#) is passed by value, unless explicitly stated otherwise. Don't be confused between true pass-by-reference (the parameter is marked either ref or out) and simply passing an object reference by value.

Posted

SOOoooo. Who is the smartest ? :)

 

 

Now my 2c:

For a VB programmer, there is not much of a difference between passing an object byval or byref. Because in either case it is possible for the sub to change the contents of the object.

 

That's what counts for me.

 

pointers are just vehicles.

objects are the precious goods.

.nerd
Posted

I was curious about all this and decided to try it out. Image and Bitmap are classes. MB is a form that shows the picture.

 

Bitmap test= (Bitmap)Image.FromFile("D:\\copy.bmp");
		a.MB.ShowDialog(test);
		testFunk(test);
		a.MB.ShowDialog(test); //The picture remains the same.
	}

	void testFunk(Bitmap b)
	{
		b= (Bitmap)Image.FromFile("D:\\pic.tif");
	}

//------------------Example 2----------------------------------

	Bitmap test= (Bitmap)Image.FromFile("D:\\copy.bmp");
		a.MB.ShowDialog(test);
		testFunk(ref test);
		a.MB.ShowDialog(test); //The picture is changed.
	}

	void testFunk(ref Bitmap b)
	{
		b= (Bitmap)Image.FromFile("D:\\pic.tif");
	}

Is C++ different than C# in this manner?

 

For example, when you pass an array in C++ it is always passed by reference and does not need the & (reference symbol in C++). I am pretty sure that the original data will always be changed. But in C#, looking at the example above, it does not seem to work that way.

C#
  • *Experts*
Posted

If you keep in mind what's going on, you'll know what to expect.

 

Reference the image below. The list of blocks at the top represent the memory occupied by the Bitmap object. Keep in mind that this is a class not a struct. The variable test is a separate piece of memory that points to the Bitmap object.

 

Since you defined the parameter b in the function without the "ref" keyword, the parameter will be passed by val. That means that the memory occupied by the variable is copied and sent to the subroutine.

 

If you look at the top portion, you'll see that I've shown "b" as a separate memory chunk that points to the same underlying data. That means when you assign b to a new Bitmap, you're only repointing that variable b's memory to a new chunk of memory (similar to the bottom portion of the picture).

 

If you changed that declaration to use "ref b" instead, then what you would be sending into the subroutine is NOT a copy of the pointer, but the actual pointer "test". That means modifying b would be modifying test, which would mean losing your old bitmap.

 

In either case, if you were to change the contents of the Bitmap (using b), such as creating a Graphics object and doing some drawing, you would affect the picture. It may appear that you've copied by reference, but it wouldn't really be true.

 

 

Now for structs.

 

Structs work just like basic datatypes (Date, String, Int, etc.) in that they are truly copied by value. In the bottom portion of the picture I've drawn what happens when you pass a struct to a function.

 

Instead of copying the pointer (but the pointer still points to the same memory as the original variable), the entire chunk of data is copied.

 

This means modifying b's data will not modify test's data. In the example above for class's, if you modify the value of a field in a struct using b.FieldA = new value, it will NOT affect the value in the variable test.

 

A final note on struct's memory.

Technically, the bottom of the picture isn't accurate as there really isn't a separate chunk of memory that points to a struct. The variable really represents the place in memory where the struct's data begins, rather than using a pointer to the real chunk of data as with a class.

 

So yes, even in C# and VB it helps to know about pointers and memory (at least as far as understanding what's going on when you declare and use objects).

 

-nerseus

"I want to stand as close to the edge as I can without going over. Out on the edge you see all the kinds of things you can't see from the center." - Kurt Vonnegut
Posted

I don't think I've ever seen the term "by reference" scewed in so many ways.

 

*sighs and goes off to watching Jay Leno*

Gamer extraordinaire. Programmer wannabe.
Posted

It's the same in C++

 

Is C++ different than C# in this manner?

 

No, it's exactly the same thing. For example, in C#, you could have something like this:

 

using System;

class A { }
class B : A { }
class C : A { }

class Test
{
   static void byval(A a)
   {
       a = new C();
   }

   static void byref(ref A a)
   {
       a = new C();
   }

   static void Main()
   {
       A a = new B();
       Console.Write(a + " => ");
       byval(a);
       Console.WriteLine(a);

       a = new B();
       Console.Write(a + " => ");
       byref(ref a);
       Console.WriteLine(a);
   }
}

 

The corresponding C++ [is there a tag for including C++?] would look something like this:

 

#include <iostream>

class A { };
class B : public A { };
class C : public A { };

void byval(A* a)
{
   a = new C();
}

void byref(A*& a)
{
   a = new C();
}

int main()
{
   A* a = new B();
   std::cout << a << " => ";
   byval(a);
   std::cout << a << std::endl;

   a = new B();
   std::cout << a << " => ";
   byref(a);
   std::cout << a << std::endl;
}

 

The results are, for C#:

 

B => B

B => C

 

and, on my computer, for C++:

 

00312C50 => 00312C50

00312C70 => 00312C80

Posted
When I don't use ref when sending a class I am not losing any performance am I?

 

No. I would suggest that you only use ref when you really need the argument to be passed by reference. That is, you need that the called method should be able to alter the value of the parameter itself.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...