Reputation: 2647
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:
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?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?Upvotes: 42
Views: 54288
Reputation: 1
in c# you can check run unsafe in your project properties and then you can run this code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Exercise_01
{
public struct Coords
{
public int X;
public int Y;
public override string ToString() => $"({X}, {Y})";
}
class Program
{
static unsafe void Main(string[] args)
{
int n = 0;
SumCallByRefPointer(1, 2, &n);
Console.Clear();
Console.WriteLine("call by refrence {0}",n);
n = 0;
SumCallByValue(3, 4, n);
Console.WriteLine("call by Value {0}", n);
n = 0;
SumCallByRef(5, 6, ref n);
Console.WriteLine("call by refrence {0}", n);
Pointer();
Console.ReadLine();
}
private static unsafe void SumCallByRefPointer(int a, int b, int* c)
{
*c = a + b;
}
private static unsafe void SumCallByValue(int a, int b, int c)
{
c = a + b;
}
private static unsafe void SumCallByRef(int a, int b, ref int c)
{
c = a + b;
}
public static void Pointer()
{
unsafe
{
Coords coords;
Coords* p = &coords;
p->X = 3;
p->Y = 4;
Console.WriteLine(p->ToString()); // output: (3, 4)
}
}
}
}
Upvotes: -1
Reputation: 11
This seems like a disposing/eventing nightmare. If I have an object who's events are registered for and pass it into a function by reference and that reference is then reallocated, the dispose should be called or the memory will be allocated until the program is closed. If the dispose is called everything registered to the objects events will no longer be registered for and everything it is registered for will no longer be registered for. How would someone keep this straight? I guess you could compare memory addresses and try to bring things back to sanity if you don't go insane.
Upvotes: 1
Reputation: 263118
A ref
in C# is equivalent to a C++ reference:
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);
Upvotes: 25
Reputation: 7961
C# has no equvalent of C++ pointers and works on references. ref
adds a level of indirection. It makes value type argument a reference and when used with reference type it makes it a reference to a reference.
In short it allows to carry any changes to a value type outside a method call. For reference type it allows to replace the original reference to a totally different object (and not just change object content). It can be used if you want to re-initialize an object inside a method and the only way to do it is to recreate it. Although I would try avoid such an approach.
So to answer your question ref
would be like C++ reference to a reference.
EDIT
The above is true for safe code. Pointers do exist in unsafe C# and are used in some very specific cases.
Upvotes: 1
Reputation: 106539
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);
}
}
Upvotes: 44
Reputation: 39916
Every reference in C# is pointer to objects on heap as pointer in C++ and ref of C# is same as & in C++
The reason ref should be avoided is, C# works on fundamental that method should not change the object passed in parameter, because for someone who does not have source of method may not know if it will result in loss of data or not.
String a = " A ";
String b = a.Trim();
In this case I am confident that a remains intact. In mathematics change should be seen as an assignment that visually tells is that b is changed here by programmer's consent.
a = a.Trim();
This code will modify a itself and the coder is aware of it.
To preserve this method of change by assignment ref should be avoided unless it is exceptional case.
Upvotes: 3