locked
Porting pin_ptr from managed c++ to c++/cli RRS feed

  • Question

  • I'm porting code from managed c++ over to c++/cli and there's a portion of code in managed c++ which resembles:

    Type __pin* name = dynamic_cast<Type *>(difName);

    I believe this is done to get the native pointer to the object instead of the managed pointer to the object.

    However when I translate this to c++/cli syntax as such:

    pin_ptr<Type> name = dynamic_cast<Type *>(difName);

    First it says: error C3699: '*' : cannot use this indirection on type 'Name', so after I replace the * with a ^ (which kind of defeats the purpose of pinning) I get the error: error C3833: 'Name' : invalid target type for pin_ptr .

    So I'm not really sure how to port the original managed c++ code, any suggestions?

    Monday, January 28, 2008 9:22 PM

Answers

  • I'm unclear on what you're trying to accomplish at this point. The purpose of pin_ptr is to pin an object so you can use that object from unmanaged code without the GC moving it in memory. If you aren't using difName or one of its members from unmanaged code, there's no point to pinning the object; if you don't need the entire object to be pinned but do need a pointer to one of the object's members, use an interior_ptr directly.

    So, under the assumption you really do need the object pinned: pin_ptr yields an interior_ptr to a member of an object, while simultaneously pinning the whole object. If you only need to pin an object, but don't need a pointer to a member of the object, then simply pin the member then ignore the pin_ptr from then on -- as long is the pin_ptr is in scope, the object won't move in memory:

    void fn(IType^ difName)
    {
    	Type^ dif = dynamic_cast<Type^>(difName);
    	pin_ptr<int> pin = &dif->pinIt;
    
    	// as long as pin is in scope and isn't reassigned, dif won't move in memory
    
    	// pin is an interior_ptr to the pinIt member, not a pointer to dif
    
    	// to access other members of dif, use dif directly, not pin; the only purpose of pin is simply to prevent dif from moving in memory
    
    	...
    }
    
    // once pin is out of scope, dif is no longer pinned in memory and is thus eligible for garbage collection.

    Again, I'm back to guessing about what you're actally trying to do, why do you need a pin_ptr?

    • Edited by ildjarn Friday, August 5, 2011 10:17 PM
    Wednesday, January 30, 2008 6:21 PM

All replies

  • What type is difName? Assuming it's a normal ref class variable, you can do:

    pin_ptr<Type> name = &difName;
    • Edited by ildjarn Friday, August 5, 2011 10:10 PM
    Monday, January 28, 2008 9:39 PM
  • difName is the same type as Type.

    When I tried the method suggested it gave me the same error. It says:  error C3833: Type : invalid target type for pin_ptr.

    I did look up the documentation on the error c3833 and it seems the method you suggested should work, however I'm guessing now that I have to use some other method to get the native object of type, Type.   
    Monday, January 28, 2008 11:14 PM
  • So.. what type is difName and how was it allocated? gcnew allocated, new allocated, stack allocated? ref class, class, enum, enum struct? etc, etc. There's a lot of guessing involved at this point, a little information from you would help a lot
    Monday, January 28, 2008 11:53 PM
  • difName is the parameter of a function, and is a managed pointer to an object. I'm not sure about the allocation. I believe its a ref class. Is there more info that could help you in diagnosing the situation? Smile

    Tuesday, January 29, 2008 6:27 PM
  • In managed C++, __pin was able to pin an entire __gc class object, but that has changed for C++/CLI. Now, pin_ptr is a special type of interior_ptr that has the effect of pinning the entire object whose member you're pointing to. In case you're not familiar with interior_ptr, it points to a member of a reference type, but not to the reference type itself.

    For example:

    ref struct CFoo
    {
    	String^ str;
    	double dbl;
    	int i;
    	Version^ ver;
    };
    
    void fn(CFoo^ foo)
    {
    	// Any of the following have the effect of pinning foo
    	pin_ptr<String^> str = &foo->str;
    	pin_ptr<double> dbl = &foo->dbl;
    	pin_ptr<int> i = &foo->i;
    	pin_ptr<Version^> ver = &foo->ver;
    
    	// The following DO NOT work:
    	// Even though the second one compiles, it does not actually
    	//  pin foo, it pins the local handle to foo
    	pin_ptr<CFoo> pfoo1 = &foo;
    	pin_ptr<CFoo^> pfoo2 = &foo;
    }

    So in your case, because Type is a ref class, you cannot create a pin_ptr to difName as a whole. Instead you must make a pin_ptr to one of difName's public members.

    See the following links for more information:

    http://msdn2.microsoft.com/en-us/library/y0fh545k.aspx

    http://msdn2.microsoft.com/en-us/library/1dz8byfh.aspx

    http://msdn2.microsoft.com/en-us/library/ms235267(VS.80).aspx

    • Edited by ildjarn Friday, August 5, 2011 10:13 PM
    Tuesday, January 29, 2008 8:35 PM
  • Oh ok that makes sense. However the only problem I have now is that the only public members are properties and methods. I'm not sure how to apply the method you used for pinning to properties. For example I just tried this:
    If there was a property called:

    Code Snippet

    Property String^ propName{},


    I pinned the ref class by doing:

    Code Snippet

    pin_ptr<String ^> Name = &difName->propName;


    However that gave me the error:  error C2102: '&' requires l-value


    Tuesday, January 29, 2008 9:42 PM
  • If you have the source code to the Type class and it isn't impractical to change it, you can add a public member field (bool or int or whatever, something that's a small value type) to the class just for pinning purposes. Alternatively, you can change the property to return a tracking reference to a handle instead of just a handle, since tracking references are always l-values:

    property String^% propName { String^% get() { return m_propName; } }

    If you dont have the source code for Type or it's impractical to change, I think you may be out of luck.

     

    EDIT: I guess one possible ugly workaround may be to make a wrapper class for Type just for pinning purposes:

    template<typename T>
    ref struct CPinner sealed
    {
    	T^ obj;
    	CPinner(T^ o) : obj(o) { }
    };
    
    void fn(Type^ difName)
    {
    	CPinner<Type> pinner = gcnew CPinner<Type>(difName);
    	pin_ptr<Type^> name = &pinner->obj;
    	// difName is now pinned for the scope of name;
    }

    Again, this is only necessary if Type has no accessible member fields.

    • Edited by ildjarn Friday, August 5, 2011 10:15 PM
    Tuesday, January 29, 2008 10:10 PM
  • Wow, sorry I just realized something. Originally I said difName was of type: Type. But its not, its of a different type. difName is an interface class. And the parameter thing still applies, but its just not of type: Type as I had said before, its of type: IType. I'm guessing that changes that way I would go about pinning? Stick out tongue
    Tuesday, January 29, 2008 11:18 PM
  • No, you'll just have to use the wrapper class workaround I showed in my last post, since interface classes cannot have instance member fields to pin on.

     

    Tuesday, January 29, 2008 11:24 PM
  • The thing is though, I'm not pinning to the interface type, I'm pinning to a ref class type, but then I have to assign that pin_ptr to something that is an interface type, so in the original mc++ this interface type was dynamically cast to the ref class type that was being pinned.

    So somehow I have to pin the ref class and assign it to an interface type which has been casted to a ref class type. Hence the original attempt was:

    Code Snippet

    pin_ptr<Type> name = dynamic_cast<Type ^>(difName);



    The Type for the pin_ptr is a ref class, but difName is an interface type and hence was being cast before being assigned to the pin_ptr.

    Edit:

    I tried this method:

    I declared a new variable of type: Type ^ and casted the interface type to the ref class type like so:

    Code Snippet

    Type ^ pinner = dynamic_cast<Type ^>(difName);



    Then I did what you originally suggested by declaring an int variable in the ref class for pinning purposes and assigned the pin_ptr as such:

    Code Snippet

     pin_ptr<int> name = &pinner->pinIt;


    This allowed me to pin the object, however since there is a subsequent part of code that tries to access a property by going:

    Code Snippet

    name->propName;


    The compiler complains that this property is not a member of System::Int32.

    Wednesday, January 30, 2008 5:34 PM
  • I'm unclear on what you're trying to accomplish at this point. The purpose of pin_ptr is to pin an object so you can use that object from unmanaged code without the GC moving it in memory. If you aren't using difName or one of its members from unmanaged code, there's no point to pinning the object; if you don't need the entire object to be pinned but do need a pointer to one of the object's members, use an interior_ptr directly.

    So, under the assumption you really do need the object pinned: pin_ptr yields an interior_ptr to a member of an object, while simultaneously pinning the whole object. If you only need to pin an object, but don't need a pointer to a member of the object, then simply pin the member then ignore the pin_ptr from then on -- as long is the pin_ptr is in scope, the object won't move in memory:

    void fn(IType^ difName)
    {
    	Type^ dif = dynamic_cast<Type^>(difName);
    	pin_ptr<int> pin = &dif->pinIt;
    
    	// as long as pin is in scope and isn't reassigned, dif won't move in memory
    
    	// pin is an interior_ptr to the pinIt member, not a pointer to dif
    
    	// to access other members of dif, use dif directly, not pin; the only purpose of pin is simply to prevent dif from moving in memory
    
    	...
    }
    
    // once pin is out of scope, dif is no longer pinned in memory and is thus eligible for garbage collection.

    Again, I'm back to guessing about what you're actally trying to do, why do you need a pin_ptr?

    • Edited by ildjarn Friday, August 5, 2011 10:17 PM
    Wednesday, January 30, 2008 6:21 PM
  • Yes thankyou it worked. Using pin worked, it compiled successfully!
    Wednesday, January 30, 2008 6:27 PM