Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# ref is it like a pointer in C/C++ or a reference in C++?

I'm working with the ref and don't understand clearly "Is it like a pointer as in C/C++ or it's like a reference in C++?"

Why did I ask such a weak question as you thought for a moment? Because, when I'm reading C#/.NET books, msdn or talking to C# developers I'm becoming confused by the following reasons:

  • C# developers suggest NOT to use ref in the arguments of a function, e.g. ...(ref Type someObject) doesn't smell good for them and they suggest ...(Type someObject), I really don't understand clearly this suggestion. The reasons I heard: better to work with the copy of object, then use it as a return value, not to corrupt memory by a reference etc... Often I hear such explanation about DB connection objects. As on my plain C/C++ experience, I really don't understand why to use a reference is a bad stuff in C#? I control the life of object and its memory allocations/re-allocations etc... I read in books and forums only advises it's bad, because you can corrupt your connection and cause a memory leak by a reference lose, so I control the life of object, I may control manually what I really want, so why is it bad?
  • Nowadays reading different books and talk to different people, I don't clearly understand is ref a pointer (*) or a reference like in C++ by & ? As I remember pointers in C/C++ always do allocate a space with a size of void* type - 4 bytes (the valid size depends on architecture), where hosts an address to a structure or variable. In C++ by passing a reference & there is no new allocations from the heap/stack and you work with already defined objects in memory space and there is no sub-allocating memory for a pointer externally like in plain C. So what's the ref in C#? Does .NET VM handle it like a pointer in plain C/C++ and its GC allocates temporary space for a pointer or it does a work like reference in C++? Does ref work only with a managed types correctly or for value types like bool, int it's better to switch an unsafe code and pass through a pointer in unmanaged style?
like image 727
Secret Avatar asked Apr 25 '13 06:04

Secret


2 Answers

In C#, when you see something referring to a reference type (that is, a type declared with class instead of struct), then you're essentially always dealing with the object through a pointer. In C++, everything is a value type by default, whereas in C# everything is a reference type by default.

When you say "ref" in the C# parameter list, what you're really saying is more like a "pointer to a pointer." You're saying that, in the method, that you want to replace not the contents of the object, but the reference to the object itself, in the code calling your method.

Unless that is your intent, then you should just pass the reference type directly; in C#, passing reference types around is cheap (akin to passing a reference in C++).

Learn/understand the difference between value types and reference types in C#. They're a major concept in that language and things are going to be really confusing if you try to think using the C++ object model in C# land.

The following are essentially semantically equivalent programs:

#include <iostream>  class AClass {     int anInteger; public:     AClass(int integer)         : anInteger(integer)     {  }      int GetInteger() const     {         return anInteger;     }      void SetInteger(int toSet)     {         anInteger = toSet;     } };  struct StaticFunctions {     // C# doesn't have free functions, so I'll do similar in C++     // Note that in real code you'd use a free function for this.      static void FunctionTakingAReference(AClass *item)     {         item->SetInteger(4);     }      static void FunctionTakingAReferenceToAReference(AClass **item)     {         *item = new AClass(1729);     } };  int main() {     AClass* instanceOne = new AClass(6);     StaticFunctions::FunctionTakingAReference(instanceOne);     std::cout << instanceOne->GetInteger() << "\n";      AClass* instanceTwo;     StaticFunctions::FunctionTakingAReferenceToAReference(&instanceTwo);     // Note that operator& behaves similar to the C# keyword "ref" at the call site.     std::cout << instanceTwo->GetInteger() << "\n";      // (Of course in real C++ you're using std::shared_ptr and std::unique_ptr instead,     //  right? :) )     delete instanceOne;     delete instanceTwo; } 

And for C#:

using System;  internal class AClass {     public AClass(int integer)         : Integer(integer)     {  }      int Integer { get; set; } }  internal static class StaticFunctions {     public static void FunctionTakingAReference(AClass item)     {         item.Integer = 4;     }      public static void FunctionTakingAReferenceToAReference(ref AClass item)     {         item = new AClass(1729);     } }  public static class Program {     public static void main()     {         AClass instanceOne = new AClass(6);         StaticFunctions.FunctionTakingAReference(instanceOne);         Console.WriteLine(instanceOne.Integer);          AClass instanceTwo  = new AClass(1234); // C# forces me to assign this before                                                 // it can be passed. Use "out" instead of                                                 // "ref" and that requirement goes away.         StaticFunctions.FunctionTakingAReferenceToAReference(ref instanceTwo);         Console.WriteLine(instanceTwo.Integer);     } } 
like image 77
Billy ONeal Avatar answered Oct 01 '22 01:10

Billy ONeal


A ref in C# is equivalent to a C++ reference:

  • Their intent is pass-by-reference
  • There are no null references
  • There are no uninitialized references
  • You cannot rebind references
  • When you spell the reference, you are actually denoting the referred variable

Some C++ code:

void foo(int& x) {     x = 42; } // ... int answer = 0; foo(answer); 

Equivalent C# code:

void foo(ref int x) {     x = 42; } // ... int answer = 0; foo(ref answer); 
like image 28
fredoverflow Avatar answered Oct 01 '22 03:10

fredoverflow