eldiener

Since a tracking reference is just an alias to a ref class or value class, why is there the limitation of not allowing a tracking reference to be a member of a ref or value class Clearly a variable of a ref class or value class type can be a member, so the limitation on the tracking references seems poorly designed.

I wanted to design a generic ref class with a value class T type parameter which takes a variable of that T and resets it back to the default value of that variable in the destructor of the generic class. But this is impossible since I can not hold on to any reference to the variable in my generic class because tracking references as members are not allowed. What a PITA !


Re: Visual C++ Language C++/CLI Tracking reference limitation

Nishant Sivakumar

While this is definitely not the same thing, would it fit your scenario :-

ref class R1
{
public:
R1(String^ s1) : s(s1)
{
}
String^& s;
};





Re: Visual C++ Language C++/CLI Tracking reference limitation

eldiener

Nishant Sivakumar wrote:
While this is definitely not the same thing, would it fit your scenario :-

ref class R1
{
public:
R1(String^ s1) : s(s1)
{
}
String^& s;
};


Unfortunately that will not work in a generic class, since I get the message:

error C3229: 'T &' : indirections on a generic type parameter are not allowed

Also the actual type needs to be a value type and not a ref type.

Finally, on the tracking references MSDN subject I read:

"It is not possible to have a native C++ reference to an object on the garbage-collected heap."






Re: Visual C++ Language C++/CLI Tracking reference limitation

Holger Grund

Effectively, C++ native references translate to native pointers in CLR speak. It is perfectly possible to have a native pointer to an object of a generic parameter type. However, as you've probably noticed by now there are a lot of things in VC++'s CLR support that are less than perfect.

The limitation, that managed pointers cannot be members comes from the CLR. I asked for functionality to overcome this quite early in the alpha days, basically supporting automatic allocation of objects of a given type and forcing all function calls inline. Brandon said they had considered and dismissed something like this. IIRC they called it "stackonly" types.

I doubt that there is a good solution for your problem. You may be able to pin the underlying object via the library somehow, but then it won't be beautiful.

-hg





Re: Visual C++ Language C++/CLI Tracking reference limitation

eldiener

Holger Grund wrote:

Effectively, C++ native references translate to native pointers in CLR speak. It is perfectly possible to have a native pointer to an object of a generic parameter type. However, as you've probably noticed by now there are a lot of things in VC++'s CLR support that are less than perfect.



By "native pointers" do you mean "T *" or "T ^"

The problem in generic classes is that one can not have a member function that is T ^. The obvious reason for this is that T itself may be a ref class so that T ^ now becomes T ^ ^, which is impossible. That would be fine if one could than have T % as an alias for whatever T is. But even that is forbidden, for all CLR classes, which was the point of my OP.

If in native C++ one can have a reference to any object as an alias for that object anywhere, it seems to me a great limitation of the CLR that one can not have a "reference" to any CLR object as an alias to that object anywhere. By "reference" in CLR I mean a tracking reference, %, in C++/CLI or the 'ref' keyword in C#.

There are various idioms in which one wants to hold a reference to an object, in order to operate on that object later, whether that object in CLR is a ref class or a value class, in a generic way. One of these which I was hoping to implement is a type reset generic class, where an object of a type is passed to the class in its constructor along with optionally, via a second constructor, a value to which the object is reset. When the generic class is destructed (disposed ), the object is reset either back to a value or back to its default constructor value. This is impossible to do if one can not hold a tracking reference to the original object as a member of that class.

The limitation of tracking references not being members of a class seems severe, since as I pointed out in my OP, any object which can be tracked clearly can be a member of a class, so it is really hard to understand why this aliasing limitation was established.

Holger Grund wrote:

The limitation, that managed pointers cannot be members comes from the CLR. I asked for functionality to overcome this quite early in the alpha days, basically supporting automatic allocation of objects of a given type and forcing all function calls inline. Brandon said they had considered and dismissed something like this. IIRC they called it "stackonly" types.

I doubt that there is a good solution for your problem. You may be able to pin the underlying object via the library somehow, but then it won't be beautiful.

-hg



I am not sure if what you are mentioning as "managed pointers" is what I mention as "tracking references" but I will assume it is.

I will play around with pinning pointers in a generic class, as you suggested, but I have small hope this will work.

Why Brandon Bray said they dismissed the notion of "managed pointers" I of course do not know, or what "stackonly" types have to do with it, unless a member function of a class is considered "stackonly". I do realize that tracking references are more complicated than C++ native references, since tracking references can be rebound, and maybe this has something to do with the reason that the notion of tracking references as members of classes was dismissed. Of course, just like C++ native references I would say that tracking references as members of classes, if it had been accepted, would have to be set to some actual object upon object instantiation.




Re: Visual C++ Language C++/CLI Tracking reference limitation

Holger Grund

eldiener wrote:
Holger Grund wrote:

Effectively, C++ native references translate to native pointers in CLR speak. It is perfectly possible to have a native pointer to an object of a generic parameter type. However, as you've probably noticed by now there are a lot of things in VC++'s CLR support that are less than perfect.



By "native pointers" do you mean "T *" or "T ^"

Neither :-) As I've said it is a CLR term. V%, R^%, interior_ptr, pin_ptr (but not R%) all translate to managed pointers (which to further confusion are named with "&" in ILASM).


eldiener wrote:

The problem in generic classes is that one can not have a member function that is T ^. The obvious reason for this is that T itself may be a ref class so that T ^ now becomes T ^ ^, which is impossible. That would be fine if one could than have T % as an alias for whatever T is. But even that is forbidden, for all CLR classes, which was the point of my OP.

There are some asymmetries in the semantics of ^ and %. R^ and R% both are object references. For value types, however, V^ is a boxed value type and hence an object reference. While V% is a managed pointer.

However, as I understand your problem you don't want R% but R^%. That works just fine:

Code Snippet

generic void foo( T% t ) {} // t is always a tracking reference - it cannot be R%

eldiener wrote:

If in native C++ one can have a reference to any object as an alias for that object anywhere, it seems to me a great limitation of the CLR that one can not have a "reference" to any CLR object as an alias to that object anywhere. By "reference" in CLR I mean a tracking reference, %, in C++/CLI or the 'ref' keyword in C#.

Yes that's understood. I don't know the rationale for not allowing managed pointers as members. I suspect it has something to do with GC.


eldiener wrote:

I am not sure if what you are mentioning as "managed pointers" is what I mention as "tracking references" but I will assume it is.

Yes pretty much, as I mentioned earlier.


eldiener wrote:

I will play around with pinning pointers in a generic class, as you suggested, but I have small hope this will work.



Why Brandon Bray said they dismissed the notion of "managed pointers" I of course do not know, or what "stackonly" types have to do with it, unless a member function of a class is considered "stackonly". I do realize that tracking references are more complicated than C++ native references, since tracking references can be rebound, and maybe this has something to do with the reason that the notion of tracking references as members of classes was dismissed. Of course, just like C++ native references I would say that tracking references as members of classes, if it had been accepted, would have to be set to some actual object upon object instantiation.

What it was asking for is something along the lines of:

Code Snippet

template<typename T>

auto value struct reference_wrapper {
explicit reference_wrapper( T% t ) : t_ (t) {}
~reference_wrapper() { t_ = T(); } // yes - value types could have SMFs back then

private:

T% t_;

};

Instances of these "auto" classes could only ever have automatic storage duration and hence the compiler frontend could move the data members to the local scope, consequently overcoming the limitation of managed pointers cannot be members. I've never seen any concrete syntax, but apparently it was discussed at some point and called "stackonly" types. However, the idea was not taken further.

If you really, insist on something like this you can probably use a combination of generic dispatch,interfaces that should at the very least work for locals.





Re: Visual C++ Language C++/CLI Tracking reference limitation

Nishant Sivakumar

>>
I don't know the rationale for not allowing managed pointers as members. I suspect it has something to do with GC.
<<

Yes, it's got to do with the GC. This from the MSDN docs for error C3160.

"Interior garbage collection pointers may point to the interior of a managed class. Because they are slower than whole-object pointers and require special handling by the garbage collector, you cannot declare interior managed pointers as members of a class."

But I gotta say that that's a daft reason to use for it. It breaks the idea of having a managed equivalent in C++/CLI for pretty much anything that you can do in native C++.





Re: Visual C++ Language C++/CLI Tracking reference limitation

eldiener

Holger Grund wrote:
eldiener wrote:
Holger Grund wrote:

Effectively, C++ native references translate to native pointers in CLR speak. It is perfectly possible to have a native pointer to an object of a generic parameter type. However, as you've probably noticed by now there are a lot of things in VC++'s CLR support that are less than perfect.



By "native pointers" do you mean "T *" or "T ^"

Neither :-) As I've said it is a CLR term. V%, R^%, interior_ptr, pin_ptr (but not R%) all translate to managed pointers (which to further confusion are named with "&" in ILASM).


eldiener wrote:

The problem in generic classes is that one can not have a member function that is T ^. The obvious reason for this is that T itself may be a ref class so that T ^ now becomes T ^ ^, which is impossible. That would be fine if one could than have T % as an alias for whatever T is. But even that is forbidden, for all CLR classes, which was the point of my OP.

There are some asymmetries in the semantics of ^ and %. R^ and R% both are object references. For value types, however, V^ is a boxed value type and hence an object reference. While V% is a managed pointer.

However, as I understand your problem you don't want R% but R^%. That works just fine:

Code Snippet

generic void foo( T% t ) {} // t is always a tracking reference - it cannot be R%

eldiener wrote:

If in native C++ one can have a reference to any object as an alias for that object anywhere, it seems to me a great limitation of the CLR that one can not have a "reference" to any CLR object as an alias to that object anywhere. By "reference" in CLR I mean a tracking reference, %, in C++/CLI or the 'ref' keyword in C#.

Yes that's understood. I don't know the rationale for not allowing managed pointers as members. I suspect it has something to do with GC.


eldiener wrote:

I am not sure if what you are mentioning as "managed pointers" is what I mention as "tracking references" but I will assume it is.

Yes pretty much, as I mentioned earlier.


eldiener wrote:

I will play around with pinning pointers in a generic class, as you suggested, but I have small hope this will work.



Why Brandon Bray said they dismissed the notion of "managed pointers" I of course do not know, or what "stackonly" types have to do with it, unless a member function of a class is considered "stackonly". I do realize that tracking references are more complicated than C++ native references, since tracking references can be rebound, and maybe this has something to do with the reason that the notion of tracking references as members of classes was dismissed. Of course, just like C++ native references I would say that tracking references as members of classes, if it had been accepted, would have to be set to some actual object upon object instantiation.

What it was asking for is something along the lines of:

Code Snippet

template<typename T>

auto value struct reference_wrapper {
explicit reference_wrapper( T% t ) : t_ (t) {}
~reference_wrapper() { t_ = T(); } // yes - value types could have SMFs back then

private:

T% t_;

};

Instances of these "auto" classes could only ever have automatic storage duration and hence the compiler frontend could move the data members to the local scope, consequently overcoming the limitation of managed pointers cannot be members. I've never seen any concrete syntax, but apparently it was discussed at some point and called "stackonly" types. However, the idea was not taken further.

If you really, insist on something like this you can probably use a combination of generic dispatch,interfaces that should at the very least work for locals.



My TypeReset code is:

Header file, TSETypeReset.h

Code Snippet

#pragma once
namespace ns {
generic <typename T>
where T: gcnew()
public ref class TypeReset
{
public:
TypeReset(T % refT,T valueT);
TypeReset(T % refT);
~TypeReset();
private:
T % r;
T v;
};
}



Source file TSETypeReset.cpp

Code Snippet

#include "stdafx.h"
#include "TSETypeReset.h"
generic <typename T>
ns::TypeReset<T>::TypeReset(T % refT,T valueT) :
r(refT),v(valueT)
{
}
generic <typename T>
ns::TypeReset<T>::TypeReset(T & refT) :
r(refT),v(gcnew T)
{
}
generic <typename T>
ns::TypeReset<T>::~TypeReset()
{
r = v;
}


But of course because 'T % r' as a class member is illegal, this does not work. Notice that if 'T % r' was legal, it should work for ref or value class T.






Re: Visual C++ Language C++/CLI Tracking reference limitation

eldiener

Nishant Sivakumar wrote:
>>
I don't know the rationale for not allowing managed pointers as members. I suspect it has something to do with GC.
<<

Yes, it's got to do with the GC. This from the MSDN docs for error C3160.

"Interior garbage collection pointers may point to the interior of a managed class. Because they are slower than whole-object pointers and require special handling by the garbage collector, you cannot declare interior managed pointers as members of a class."

But I gotta say that that's a daft reason to use for it. It breaks the idea of having a managed equivalent in C++/CLI for pretty much anything that you can do in native C++.


If "interior garbage collection pointers" above means what I was hoping for, which is tracking references as members of a class, it makes not sense to say that these pointers may point to the interior of a managed class, and therefore they are forbidden. Tracking references can just as soon point to whole objects, such as value class or ref class objects, so the entry above about interior pointers is just a red herring attempting to mask Microsoft's refusal to allow tracking references to be members of a CLR class. C++/CLI alread has interior_ptr, which is a completely different concept from a tracking reference, so I have no idea why one is linked to the other in any way.

I assume if a tracking reference were allowed as a member of a class, and that tracking reference actually "pointed" to a class member rather than a whole object, then it would be an error since it should be an interior_ptr instead. But this is no different than from the way things are now without tracking references being allowed as members of a class.

Again I think it is a big design mistake that whereas in C++ reference objects can be class members, in .Net their equivalent, tracking references, can not be.

As related to GC, if tracking references were allowed as members of a class, they would add to just another "pointer" which GC would keep track of before deciding to clean up an object. Of course this may be the real issue. Perhaps Microsoft did not want to add code to GC to also keep track of tracking references along with the more normal references ( ^ in C++/CLI ) to the GC heap. But one pays for such a decision in lost functionality.