reference arg

  • Thread starter Thread starter Ian Lazarus
  • Start date Start date
I

Ian Lazarus

Hello,

If a function arg is a reference to a built in type, is it necessary for the
function definition to specify whether the reference is to a managed or
un-managed object? If so, does that mean that there needs to be two
(otherwise duplicate) functions in order for both types of objects to be
processed? E.g.,

void foo(int __gc & x);
void foo(int __nogc & x);

Thanks
 
Ian,
If a function arg is a reference to a built in type, is it necessary for the
function definition to specify whether the reference is to a managed or
un-managed object? If so, does that mean that there needs to be two
(otherwise duplicate) functions in order for both types of objects to be
processed? E.g.,

void foo(int __gc & x);
void foo(int __nogc & x);

That depends. You're not talking here about the object being
managed/unmanaged, just whether it is being referenced by a tracking pointer
(__gc) or a non-tracking pointer (__nogc).

In many cases, it won't be useful to have both overloads; if you're working
mostly on the managed side, then the __gc version is preffered because its
the one that other languages (like C#) can understand.
 
Thanks but the function in question has no way of knowing whether its
arguments will reside on the managed heap or on the stack. It needs to
handle both. So what do I do?
 
Ian said:
Thanks but the function in question has no way of knowing whether its
arguments will reside on the managed heap or on the stack. It needs to
handle both. So what do I do?

You can get away with just the __gc& version, as it can bind to both managed
and unmanaged references. As for what you need to do, it appears that
overloading doesn't quite work with __gc references as it does with __gc
pointers. For instance, the example in the "Managed Extensions for C++
Specification", "7.6 __gc Pointers and Overload Resolution", does not work
for references, producing the error below on the f(i) call, i being an
unmanaged int:

b.cpp(13) : error C2668: 'f' : ambiguous call to overloaded function
b.cpp(6): could be 'void f(int __gc &)'
b.cpp(5): or 'void f(int &)'
while trying to match the argument list '(int)'

Get rid of the int& overload, and it compiles fine.
 
Ian said:
Hello,

If a function arg is a reference to a built in type, is it necessary for the
function definition to specify whether the reference is to a managed or
un-managed object? If so, does that mean that there needs to be two
(otherwise duplicate) functions in order for both types of objects to be
processed? E.g.,

void foo(int __gc & x);
void foo(int __nogc & x);


If you want to pass a reference of an int (either on the stack or the
unmanaged heap), a

void foo(int &x);


would suffice.




If you want to pass an int placed in the managed heap, that is:


int __gc *p = new int(5);


then you may use:

void f(int __gc &x)



However you can always pin the managed object and use the native version:


#using <mscorlib.dll>


void f(int &x)
{
}


int main()
{
using namespace System;

int __gc *p = new int(5);

int __pin *pinp = p;

f(*pinp);

// Unpin
pinp=0;
}




However pinning is considered dangerous for people who do not know what
they are doing.
 
Ioannis said:
However pinning is considered dangerous for people who do not know what
they are doing.

However I just noticed that



#using <mscorlib.dll>


void f(int __gc &x)
{
}


int main()
{
int x= 1;

f(x);
}



as well as


#using <mscorlib.dll>


void f(int __gc &x)
{
}


int main()
{
int __nogc *p= new int(10);

f(*p);
}



both compile. So you can do with the managed version for both cases.
 
Ioannis said:
However I just noticed that



#using <mscorlib.dll>


void f(int __gc &x)
{
}


int main()
{
int x= 1;

f(x);
}



as well as


#using <mscorlib.dll>


void f(int __gc &x)
{
}


int main()
{
int __nogc *p= new int(10);

f(*p);
}



both compile. So you can do with the managed version for both cases.



This happens because in .NET int is not an unmanaged type but a *value*
type.
 
Is there a significant difference between the two? (The __nogc is redundant,
BTW. For that matter, you can't use __gc new to create an int.)
This happens because in .NET int is not an unmanaged type but a *value*
type.

#using <mscorlib.dll>

struct X
{
};

void f(X __gc&);

void g()
{
X x;
f(x);
}

So, I think __gc references (and pointers) can bind to __nogc objects
(__value or not) simply because that's the way they're defined.
 
What do you mean by "...that's the way they're defined."? My understanding
is that __gc indicates to the compiler that the object is located on the
"common runtime heap" , i.e., the heap which the garbage collector is
managing. A __nogc object, in contrast, is defined to not exist on the
common runtime heap, That is my understanding of what the definitions of
__gc and __nogc are.
 
Ian said:
What do you mean by "...that's the way they're defined."? My understanding
is that __gc indicates to the compiler that the object is located on the
"common runtime heap" , i.e., the heap which the garbage collector is
managing. A __nogc object, in contrast, is defined to not exist on the
common runtime heap, That is my understanding of what the definitions of
__gc and __nogc are.

MS defined __gc references and pointers to have the ability to bind to
__nogc objects (__value or not).
 
Doug said:
MS defined __gc references and pointers to have the ability to bind to
__nogc objects (__value or not).



__gc pointers used like that are probably the so called interior_ptrs of
C++/CLI.

In C++/CLI (0.8 draft) they are more restricted to value types only.
 
Ioannis said:
__gc pointers used like that are probably the so called interior_ptrs of
C++/CLI.

In C++/CLI (0.8 draft) they are more restricted to value types only.

Whew, I've got the 1.5 draft, and having read 12.3.6 a couple of times, I'm
still not sure I understand interior_ptrs. However, according to 12.3.5,
tracking references can bind to both gc-lvalues and ordinary lvalues, so the
OP's question persists in C++/CLI. I wonder if overloading on tracking works
in Whidbey? (I can't test right at this moment.) The analogous overloading
doesn't work for references in VC7.1, though it does work for pointers, as I
mentioned in my message to the OP.
 
Doug said:
Ioannis Vranos wrote:




Whew, I've got the 1.5 draft,


My mistake, I meant the 1.8 draft:

http://www.plumhall.com/C++-CLI draft 1.8.pdf


and having read 12.3.6 a couple of times, I'm
still not sure I understand interior_ptrs.


In simple words (as pin_ptrs) they are handles converted to pointers.

interior_ptrs do not pin though, and their value gets updated when the
object is moved.


However, according to 12.3.5,
tracking references can bind to both gc-lvalues and ordinary lvalues, so the
OP's question persists in C++/CLI.


Yes for all objects a % reference works.

I wonder if overloading on tracking works
in Whidbey? (I can't test right at this moment.) The analogous overloading
doesn't work for references in VC7.1, though it does work for pointers, as I
mentioned in my message to the OP.


Well, the code


void f(int %) {}

void f(int &) {}



int main()
{
int x;

f(x);
}


produces:

C:\c>cl /clr temp.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 14.00.40904
for Microsoft (R) .NET Framework version 2.00.40607.16
Copyright (C) Microsoft Corporation. All rights reserved.

temp.cpp
temp.cpp(11) : error C2668: 'f' : ambiguous call to overloaded function
temp.cpp(3): could be 'void f(int &)'
temp.cpp(1): or 'void f(int %)'
while trying to match the argument list '(int)'

C:\c>



which is quite reasonable.
 
Ioannis said:
Well, the code


void f(int %) {}

void f(int &) {}



int main()
{
int x;

f(x);
}


produces:

C:\c>cl /clr temp.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 14.00.40904
for Microsoft (R) .NET Framework version 2.00.40607.16
Copyright (C) Microsoft Corporation. All rights reserved.

temp.cpp
temp.cpp(11) : error C2668: 'f' : ambiguous call to overloaded function
temp.cpp(3): could be 'void f(int &)'
temp.cpp(1): or 'void f(int %)'
while trying to match the argument list '(int)'

C:\c>



which is quite reasonable.

Then it's like VC7.1. However, like I wrote to the OP:

<q>
As for what you need to do, it appears that
overloading doesn't quite work with __gc references as it does with __gc
pointers. For instance, the example in the "Managed Extensions for C++
Specification", "7.6 __gc Pointers and Overload Resolution", does not work
for references, producing the error below on the f(i) call, i being an
unmanaged int:

b.cpp(13) : error C2668: 'f' : ambiguous call to overloaded function
b.cpp(6): could be 'void f(int __gc &)'
b.cpp(5): or 'void f(int &)'
while trying to match the argument list '(int)'

Get rid of the int& overload, and it compiles fine.
</q>

I don't see why it should work for pointers but not for references.
 
Doug said:
I don't see why it should work for pointers but not for references.


Well, since tracking references work for both managed (ref and value)
types and unmanaged types, then in the presence of both a tracking
reference and a regular one, for an unmanaged type, we have an
ambiguity, since both fit.
 
Ioannis said:
Well, since tracking references work for both managed (ref and value)
types and unmanaged types, then in the presence of both a tracking
reference and a regular one, for an unmanaged type, we have an
ambiguity, since both fit.

In the __gc/__nogc world, which is (was? :) the subject of this thread, you
can overload pointers on the basis of __gc-ness. You can't do that with
references, which is an asymmetry. I don't know if it's intentional or not.

In C++/CLI, tracking references can bind to managed and native objects; see
for example:

http://msdn2.microsoft.com/library/hxad2z4x.aspx

But you still can't overload on "tracking" (which in Managed C++, was
__gc-ness).

Concerning pointers in C++/CLI, you can overload on interior_ptr and native
pointers:

http://msdn2.microsoft.com/library/wzkbta4k.aspx

So the situation is the same in C++/CLI, for the OP's purposes, at least,
and so is the asymmetry.
 
Back
Top