Does C++/CX detect and solve cycles of objects?
Asked Answered
P

6

12

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"?

Paeon answered 16/9, 2011 at 7:1 Comment(5)
Why should it detect the cycle? It cannot dispose neither, since both are in use, when you delete the last of those two objects, both will be free'd. Done.Familiar
There are well known cycle-detection algorithms for reference counted GCs... secure.wikimedia.org/wikipedia/en/wiki/…Zubkoff
@RedX: If C++/WinRT doesn't handle cycles the application will leak memory.Paeon
@CAFxX: WinRT doesn't use a GC.Paeon
WinRT itself supports weak references - have a look at "C:\Program Files (x86)\Windows Kits\8.0\Include\winrt\WeakReference.idl". I don't yet know how it is projected to VC++ language extensions, though.Om
O
12

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.

Om answered 17/9, 2011 at 8:5 Comment(5)
hmm. another reason not to have created the C++/CX extensions and stuck with the weak_ptr<wrapper class> like we all want it to be :)Lainelainey
@Lainelainey Please keep in mind that this describes the status quo as of Developer Preview. It doesn't mean that things will remain the same in future releases.Om
of course, and Microsoft can have all my applauds if it listens to us and changes the nasty .NET-style interface to a more native looking one. I guess this is a chance for MS to contribute to the Modules spec that unfortunately didn't make it into the latest standard, now a Boost::Modules that also works as a way to access WinRT components, that'd be good.Lainelainey
@Lainelainey C++/CX is not forced on you - if you prefer vanilla C++ with smart pointer templates etc, you can use that - regular IDL files are supplied for all WinRT interfaces, and WRL is the helper library with ComPtr<T> and other stuff. See this video for more details: channel9.msdn.com/Shows/C9-GoingNative/…Om
I've rewritten the answer to match the current state of affairs in beta (which has proper weak reference support in C++/CX).Om
L
1

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

Langue answered 16/9, 2011 at 22:6 Comment(1)
I tried whipping up a sample using reinterpret_cast and friends to go from T^ to IWeakReferenceSource*, but the QI retuns E_NOINTERFACE for classes defined via ref class - it looks like those don't support weak interfaces (yet)? Does work for WinRT components from Windows.*, though.Om
U
0

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

Umpteen answered 16/9, 2011 at 7:23 Comment(4)
There are times when this isn't an option, such as when setting Window::Current->Content = foo in OnLaunched before returning.Paeon
@Pavel: Decref would look like t = nullptr;, probably.Leaves
There's IWeakReference so this answer isn't entirely correct. Need to find out about how to do weak references in C++/CX though.Om
From what I've heard so far, this answer is the most accurate. There's a lot of hand waving going on but nothing concrete. Pre-emptive +1.Chronological
G
0

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.

Greta answered 5/10, 2011 at 16:21 Comment(0)
S
0

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.

Straphanger answered 22/11, 2016 at 3:52 Comment(0)
L
-5

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.

Leaves answered 16/9, 2011 at 22:11 Comment(4)
This is not C++/CLI, this is VC++ Component Extensions. Syntax is (mostly) the same, semantics is not. In VC++/CX, ref class is refcountable, and copying T^ will update it automatically. No GC is involved.Om
@Pavel: Wait, so the same code can be correct C++/CLI and broken VC++ Component Extensions? That idea needs to die immediately. Or at least require a #pragma at the top of each file to specify which build environment it's written for.Leaves
Oh, now I see, you can tell which environment it's meant for based on either ref new or gcnew. Still a very trouble-prone idea, IMO.Leaves
There are other differences there (e.g. cli is now lang, and System::String is Platform::String), but you're right, one can write code that is visually indistinguishable from C++/CLI but with different semantics. C++/CLI is not officially supported in Metro style apps, however. Docs are here: msdn.microsoft.com/en-us/library/windows/apps/…; also see Herb's talk here: channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-532T - starting at 9:20Om

© 2022 - 2024 — McMap. All rights reserved.