I suggest you ...

Support c++11 unique_ptr and shared_ptr with C++/CLI

C++11 introduced move and unique_ptr, shared_ptr and weak_ptr. This new types highly improve the productivity and the robustness of C++ code. When we implement wrapper/adapter for the new for C++ code that uses unique_ptr/shared_ptr/weak_ptr we have to somehow return to raw pointers because it is only possible to store raw pointers inside of managed classes.
When it is not possible to somehow allow unique_ptr/shared_ptr/weak_ptr as members of managed C++/CLI classes (ref class/struct) my suggestion is to use a similar approach as with gcroot and to provide a wrapper for that pointer types.

67 votes
Vote
Sign in
Check!
(thinking…)
Reset
or sign in with
  • facebook
  • google
    Password icon
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    Thomas shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

    4 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      Signed in as (Sign out)
      Submitting...
      • David Hunter commented  ·   ·  Flag as inappropriate

        I was asked to clarify my comment about the using the control section of a std::shared_ptr in a managed C++/CLI class.

        As of VS 2015 the std::shared_ptr has a member std::_Ref_count_base* _Rep. The _Ref_count_base class has members like _Incref and _Decref that std::shared_ptr uses to manage the reference count.

        So the basic idea is to extract the std::_Ref_count_base* and store it in a managed version of shared_ptr which would participate in the reference counting of the unmanaged object. For instance it would decrement the refrence count in its finalizer. Ideally we could just store a pointer to the unmanaged shared_ptr but the interface does not provide any ***** mechanism to increment the reference count. Extracting the _Ref_count_base* from a std::shared_ptr requires a bit of hackery, for instance creating a fake struct with the same layout as a std::shared_ptr and using reinterpret_cast.

        Sadly the manged shared_ptr equivalent class has to be a reference type not a value type as there are no destructors on value types.

        Note I assume there are cleverer ways to do this. I gave up experimenting when I got something that worked and was reasonable.

        I could easily imagine MicroSoft doing a System.Runtime.InteropServices.SharedPtr which would be far more elegant!

      • David Hunter commented  ·   ·  Flag as inappropriate

        One alternative we use is to use something similar to Boost intrusive_ptr. Then managed objects store a raw pointer to an intrusively counted unmanaged object and participate in the reference count of that object. This of course has the usual down sides of intrusive pointers plus non deterministic garbage collection on the managed side can be an issue.

        I agree with the post that it would be great if Microsoft provided a managed interop class that could work with the control section of a std::shared_ptr to jointly control the external reference count of an unmanaged object in managed code.

      • Philippe commented  ·   ·  Flag as inappropriate

        I agree that it would be nice to support the "value" syntax for native object inside a managed class and have the compiler generate appropriate code.

        It would also be nice if classes like unique_pointer would be extended to properly works with managed types. In fact the whole STL should have been done that way instead of a STL.NET that was late and unusable).

        In fact, it look like when C++/CLI was designed (for Visual Studio 2005) that the team was not STL expert as otherwise they would have made the language in a way that it would have been possible to use almost the whole STL on native type, managed class types and managed value types...

        By the way things like lambda, function objects and all that stuff should works using the same library in a transparent way and template code written by the user should also works on both managed and native type (if it works with pointer and value type).

        Because of the poor design of C++/CLI, it is very complicated to use managed type for code that was written for native types.

        It would have been much better if managed handle would use pointer syntax and only the declaration of the class would have a modifier.

        Presently only in marginal case the effect is similar. For example, one could put a managed type "on the stack" to have it automatically disposed at the end of scope or one could call delete operator on managed types. Even the use of gcnew is stupid in that context as it make it almost impossible to write template code that works with both native pointers and managed handles without writing a lot of extra code. This is probably one of the reason why STL.NET was a failure...

      • Marián Špánik commented  ·   ·  Flag as inappropriate

        Currently we have to write code like this (I didn't check whether it compiles):

        public ref class ManagedClass
        {
        NativeClass *nativeInstance = new NativeClass();

        public:
        ~ManagedClass(){this->!ManagedClass();}
        !ManagedClass(){delete nativeInstance;}

        // methods here
        }

        A second option to the suggestion is to store the native instance by value inside the managed class. It would require changes in .NET, but it would save a lot of programmers' time. It should be something like this:
        public ref class ManagedClass
        {
        NativeClass nativeInstance; // uses automatic storage in a similar way as if it were inside a native class
        // no manual cleanup of nativeInstance needed
        }
        In worst case the compiler could translate this code to the code we currently need to write (generating code for both native destructor and managed finalizer).

      Feedback and Knowledge Base