سؤال

From my understanding C++/CX doesn't use garbage collection, it use a reference counted approach instead.

The problem with reference counting is that it cannot dispose of cycles. Cycles are usually solved using weak references, such as weak_ptr in standard C++.

But I cannot find a way in C++/CX to explicitly specify a weak reference. From that I would assume that this is handled by C++/CX itself. I am wondering how C++/CX would solve this.

For instance, look at the following code:

ref class Foo
{
public:
    Bar^ bar;
};

ref class Bar
{
public:
    Foo^ foo;
};

ref class App
{
public:
    virtual void OnLaunched(LaunchActivatedEventArgs^ args)
    {
        Foo^ foo = ref new Foo();
        Bar^ bar = ref new Bar();
        foo.bar = bar;
        bar.foo = foo;
    }
};

How does C++/CX detect this cycle?

How does C++/CX solve this cycle?

How does C++/CX decide which one of these objects should be the "root object" and which one should be the "weak reference"?

هل كانت مفيدة؟

المحلول

Short answer: No, C++/CX doesn't detect and solve cycles of objects.

Long answer: WinRT itself has a standard mechanism for weak references. On ABI level, this is defined in terms of interfaces IWeakReference and IWeakReferenceSource, which you can see in "%ProgramFiles%\Windows Kits\8.0\Include\winrt\WeakReference.idl".

In C++/CX, all your classes will automatically implement IWeakReferenceSource, and hence all their instances can be weakly referenced. To obtain and store a weak reference to an object, you should use the helper class Platform::WeakReference (defined in vccorlib.h):

Foo^ foo = ref new Foo;
Platform::WeakReference weakRef(foo);

to retrieve back the object, use Resolve<T>:

foo = weakRef.Resolve<Foo>();

As usual, you will get nullptr is the object has already been destroyed.

Other than that, an instance of WeakReference behaves more or less like a smart pointer - it's copyable, movable, comparable, assignable from nullptr, has an implicit conversion to an unspecified bool type etc.

Note that, as of VS11 Beta, IDE Intellisense will balk at WeakReference if you try to use it, underlining it with squiggles etc. The compiler can handle them just fine despite all that, though.

نصائح أخرى

Check out Include\winrt\WeakReference.h in the SDK. It define IWeakReference that can be used for this purpose.

It will the same old way of COM programming, manual thinking and adding explicit decref calls.

As Pavel Minaev said, WinRT has a standard mechanism for weak references: the IWeakReferenceSource/IWeakReference interfaces, the WRL::WeakRef helper class, and so on.

Unfortunately classes defined via ref class do not implement IWeakReferenceSource and, at least in this Developer Preview version, I could not find any way to add this interface.

A possible workaround is to implement the WinRT class without using C++/CX extensions, in 'native' C++. The WRL framework simplifies this task considerably (it does for WinRT what ATL was doing for COM).

There is one of the WinRT samples (the “DLL server authoring" sample) that shows how to implement a WinRT object without using ref. By default, classes that inherit from WRL::RuntimeClass<Interface> automatically implement IWeakReferenceSource and so provide weak references.

Mozilla XPCOM implemented Bacon's approach, and this one to some degree can be ported to WinRT if needed. Generally, avoiding tracing garbage collector is a good thing. Developers still have plenty of ways to leak memory, so it's better not to fall into delusion. Also, from the control point of view, cyclic ownership does not make sense. That's like Munchausen pulling himself out of a mire by his own hair and keeping himself floating in the air. There must be a reason for every object to exist, and reference count is the manifestation of this reason. Another manifestation is the right to modify, which gives rise to robust copy-on-write techniques highly dependent on reference counter availability. In an environments only having tracing garbage collection one either has to perform deep copy of mutable data structures to preserve it from unwanted mutations, or use immutable data structures with big penalties for small deep changes. Or convert mutable and immutable data structures back and forth. Also, it was estimated that tracing garbage collection only works fine when there is 5x required RAM available (deeply copied replicas not accounted). In comparison, conservative allocators use 2x required RAM (wasted due to fragmentation). Don't be tricked, copying garbage collector only makes allocation faster, but wastes 2.5 times more RAM than reference counted conservative garbage collector to achieve comparable performance.

Look at the Apple. They introduced TGC into Objective-C 2.0 as an optional feature, but then deprecated it, and tons of iPhone applications live without it pretty fine. iPhones are known for excellent user experience and long battery charge duration. Windows 10 freezes like hell on my 4Gb RAM PC, while Mac OS X 10.4.10 Hackintosh worked pretty smoothly on 1Gb RAM. Maybe this is related somehow, don't you think so? Maybe memory is leaked accidentally somewhere, but in the end it is hard to observe compared to freezes and enormous RAM consumption.

Enormous RAM consumption make programs swap to disk, and if they swapped to disk and then started tracing garbage collection, swapped pages are all returned back to RAM, and moving swapped pages back to RAM is notably slow. Also, when doing so, pages of other applications have to be preempted to swap file. As we know, tracing garbage collected applications use 2.5 times more RAM, so these applications have 2.5 times more chance to go to swap. Suddenly another application will also initiate garbage collection and will have to get swapped pages back to RAM, preempting pages of another applications. And it goes and goes like perpetuum mobile vice versa. Normal perpetuum mobile infinitely produces energy out of thin air, and perpetuum mobile vice versa infinitely wastes energy for nothing. Tracing garbage collection is an algorithm that never ends. It is initiated heuristically from time to time and it is only known when it's done if it had any luck. Maybe this time we'll be lucky to collect something, maybe second time, maybe third time. You leave PC for a long time in the hope it will eventually be done its business and finally let you work, but this business never ends. Suddenly two applications run tracing garbage collection at the same time and start competing for unswapped RAM. Tracing garbage collection is likely to make several subsequent accesses to the same page, so one page can go to and from swap multiple times. In an office environments only boss's PC is likely to have lots of RAM, other PCs are as cheap as possible. Also, antivirus is forcefully deployed to every office PCs, and office employees can't get rid of it. Antivirus preserves RAM for in-memory signatures, making it even scarcer, and also checks every I/O including swap file driving freezes to complete insanity. That's where the hell on Earth is.

I asked tracing garbage collectors advocates if they can observe freezes like I do, and it turns out they put a lot of RAM into their PCs (like 16Gb on a notebook!!!), use it in a single user mode, and garbage collection works fine for them this way. In the hell they will have to work with their developments on the cheapest office PCs with antivirus forcefully deployed.

So I suggest you not to look at the cycle collection problem only. Learn to love reference counting, ENJOY IT and make users enjoy your slim programs. Make most of reference counting. Robust copy-on-write for nested structures. Database connection pools with wrapped connections where connections are returned to the pool immediately when their wrapper not referenced anymore. Network transparency. RAII.

And if you really have no other options, borrow from Mozilla XPCOM. By the way, on the Windows OS Mozilla XPCOM is told to have ABI identical to that of Microsoft COM, but not sure.

Those aren't WinRT objects, those are objects of your custom type. Because you've declared them as .NET reference types (ref class) using the C++/CLI syntax, they're garbage collected like all .NET reference types, via a reachability test, not reference counting.

Win32 objects have always been reference counted, so it doesn't seem like WinRT changes anything there. It just provides the C++ RAII classes for you, under Win32 programmers wrote their own wrappers to take advantage of RAII.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top