*Experts* Nerseus Posted June 27, 2003 *Experts* Posted June 27, 2003 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 Quote "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
JABE Posted June 28, 2003 Posted June 28, 2003 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. Quote
Leaders snarfblam Posted June 29, 2003 Leaders Posted June 29, 2003 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. Quote [sIGPIC]e[/sIGPIC]
_SBradley_ Posted July 2, 2003 Posted July 2, 2003 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. Quote
Heiko Posted July 2, 2003 Posted July 2, 2003 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. Quote .nerd
aewarnick Posted July 3, 2003 Author Posted July 3, 2003 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. Quote C#
*Experts* Nerseus Posted July 3, 2003 *Experts* Posted July 3, 2003 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 Quote "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
wyrd Posted July 3, 2003 Posted July 3, 2003 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* Quote Gamer extraordinaire. Programmer wannabe.
aewarnick Posted July 4, 2003 Author Posted July 4, 2003 When I don't use ref when sending a class I am not losing any performance am I? Quote C#
_SBradley_ Posted July 4, 2003 Posted July 4, 2003 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 Quote
_SBradley_ Posted July 4, 2003 Posted July 4, 2003 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. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.