2020-05-17

45: How to Use or Not Use '::com::sun::star::uno::Reference'

<The previous article in this series | The table of contents of this series | The next article in this series>

In order to avoid fatal errors (like segmentation fault errors), inadvertent inefficiencies, and tedious coding, in handling local/remote UNO objects

Topics


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: C++

The table of contents of this article


Starting Context



Target Context


  • The reader will know how to use or not use '::com::sun::star::uno::Reference' safely, efficiently, and handily in handling local or remote UNO objects.

Main Body


1: Causing Some Fatal Errors in Handling Local UNO Objects


Stage Direction
Here are Hypothesizer 7, Objector 45A, and Objector 45B in front of a computer.

Stage Direction
Objector 45A shouts, staring at the computer screen.

Objector 45A
What, the hell, is this?!

Hypothesizer 7
Sir, that is a computer screen.

Objector 45A
. . . I didn't mean that; I mean this!

Stage Direction
Objector 45A points at a point on the computer screen.

Hypothesizer 7
That is a point on the computer screen; I suppose a point in the 10 radius circle centered at (242, 1012) in pixel coordinates.

Objector 45A
Really? Does your vision have such accuracy? Anyway, what's this message?

Hypothesizer 7
Do you mean that I should tell you that it says "double free or corruption (out)"?

Objector 45A
I can read that. . . . I mean, why the error? What's wrong with my code?

Hypothesizer 7
You know, I cannot know what is wrong with your code, without seeing your code.

Stage Direction
Objector 45A shows a piece of his code on the screen. Hypothesizer 7 surveys the piece.

@C++ Source Code
					UnoDispatchCommandEventsListener l_unoDispatchCommandEventsListener;
					UnoGeneralEventsListener l_unoGeneralEventsListener;
					
					l_unoDispatchCommandEventsListener.addEventListener (&l_unoGeneralEventsListener);
					l_unoDispatcher->addStatusListener (&l_unoDispatchCommandEventsListener, *l_urlInURL);
					cout << "### dispatchWithNotification  () is being called." << endl << flush;
					l_unoDispatcher->dispatchWithNotification (*l_urlInURL, l_unoDispatchArgumentPropertiesSequence, &l_unoDispatchCommandEventsListener);
					cout << "### dispatchWithNotification  () has returned." << endl << flush;
					l_unoDispatcher->removeStatusListener (&l_unoDispatchCommandEventsListener, *l_urlInURL);
					l_unoDispatchCommandEventsListener.additionalMethod ();
					l_unoDispatchCommandEventsListener.dispose ();

Hypothesizer 7
. . . You have created the local UNO objects, 'l_unoDispatchCommandEventsListener' and 'l_unoGeneralEventsListener', in the stack.

Objector 45A
Is that wrong?

Hypothesizer 7
Not necessarily. Would you show me the definition of the UNO components?

Objector 45A
They accords to your instruction.

Stage Direction
Objector 45A shows the definitions of 'UnoDispatchCommandEventsListener' and 'UnoGeneralEventsListener' on the screen. Hypothesizer 7 surveys the definitions.

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilities_unoComponentBases_UnoComponentBase_hpp__
	#define __theBiasPlanet_unoUtilities_unoComponentBases_UnoComponentBase_hpp__
	
	#include <string>
	#include <com/sun/star/lang/XUnoTunnel.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	#include <cppuhelper/compbase1.hxx>
	#include "theBiasPlanet/unoUtilities/visualCplusplusSpecificHeaders/VisualCplusplusSpecificDefinitions.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	
	namespace theBiasPlanet {
		namespace unoUtilities {
			namespace unoComponentBases {
				class __theBiasPlanet_unoUtilities_symbolExportingOrImportingForVisualCplusplus__ UnoComponentBase: public WeakImplHelper1 <XUnoTunnel> {
					private:
						string const i_unoComponentName;
					public:
						UnoComponentBase (string const & a_unoComponentName);
						virtual ~UnoComponentBase ();
						virtual string const & getUnoComponentName ();
						virtual void SAL_CALL acquire () throw () override;
						virtual void SAL_CALL release () throw () override;
						virtual sal_Int64 SAL_CALL getSomething (Sequence <sal_Int8> const & a_datumIdentification) override;
				};
			}
		}
	}
#endif

#include "theBiasPlanet/unoUtilities/unoComponentBases/UnoComponentBase.hpp"
#include "theBiasPlanet/coreUtilities/messagingHandling/Publisher.hpp"
#include "theBiasPlanet/coreUtilities/stringsHandling/StringHandler.hpp"

using namespace ::theBiasPlanet::coreUtilities::messagingHandling;
using namespace ::theBiasPlanet::coreUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace unoUtilities {
		namespace unoComponentBases {
			UnoComponentBase::UnoComponentBase (string const & a_unoComponentName): WeakImplHelper1 <XUnoTunnel> (), i_unoComponentName (a_unoComponentName) {
				Publisher::logDebugInformation (StringHandler::format ("### An instance of a local UNO component, '%s', is being created.", i_unoComponentName));
			}
			
			UnoComponentBase::~UnoComponentBase () {
				Publisher::logDebugInformation (StringHandler::format ("### An instance of a local UNO component, '%s', is being deleted.", i_unoComponentName));
			}
			
			string const & UnoComponentBase::getUnoComponentName () {
				return i_unoComponentName;
			}
			
			void SAL_CALL UnoComponentBase::acquire () throw () {
				Publisher::logDebugInformation (StringHandler::format ("### An instance of a local UNO component, '%s', is being pointed to.", i_unoComponentName));
				WeakImplHelper1 <XUnoTunnel>::acquire ();
			}
			
			void SAL_CALL UnoComponentBase::release () throw () {
				Publisher::logDebugInformation (StringHandler::format ("### An instance of a local UNO component, '%s', is being de-pointed to.", i_unoComponentName));
				WeakImplHelper1 <XUnoTunnel>::release ();
			}
			
			sal_Int64 SAL_CALL UnoComponentBase::getSomething (Sequence <sal_Int8> const & a_datumIdentification) {
				return (sal_Int64) this;
			}
		}
	}
}

	#include <set>
	#include <com/sun/star/frame/FeatureStateEvent.hpp>
	#include <com/sun/star/frame/XDispatchResultListener.hpp>
	#include <com/sun/star/frame/XStatusListener.hpp>
	#include <com/sun/star/lang/XComponent.hpp>
	#include <com/sun/star/lang/XEventListener.hpp>
	#include <com/sun/star/uno/Reference.hxx>
	#include <cppuhelper/compbase3.hxx>
	#include "theBiasPlanet/unoUtilities/unoComponentBases/UnoComponentBase.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::frame;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	using namespace ::theBiasPlanet::unoUtilities::unoComponentBases;
	
				class UnoDispatchCommandEventsListener: public ImplInheritanceHelper3 <UnoComponentBase, XComponent, XDispatchResultListener, XStatusListener> {
					private:
						set <Reference <::com::sun::star::lang::XEventListener>> i_eventsListeners;
					public:
						UnoDispatchCommandEventsListener ();
						virtual ~UnoDispatchCommandEventsListener ();
						virtual void SAL_CALL dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) override;
						virtual void SAL_CALL statusChanged (FeatureStateEvent const & a_featureStateEvent) override;
						virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_source) override;
						virtual void SAL_CALL dispose () override;
						virtual void SAL_CALL addEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual void SAL_CALL removeEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual void additionalMethod ();
				};

#include <iostream>
			UnoDispatchCommandEventsListener::UnoDispatchCommandEventsListener (): ImplInheritanceHelper3 <UnoComponentBase, XComponent, XDispatchResultListener, XStatusListener> (string ("::theBiasPlanet::unoUtilitiesTests::localUnoObjectsTest1::UnoDispatchCommandEventsListener")) {
				cout << "### 'UnoDispatchCommandEventsListener::UnoDispatchCommandEventsListener ()' is called." << endl << flush;
			}
			
			UnoDispatchCommandEventsListener::~UnoDispatchCommandEventsListener () {
				cout << "### 'UnoDispatchCommandEventsListener::~UnoDispatchCommandEventsListener ()' is called." << endl << flush;
			}
			
			void UnoDispatchCommandEventsListener::dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) {
				cout << "### 'UnoDispatchCommandEventsListener::dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent)' is called." << endl << flush;
			}
			
			void UnoDispatchCommandEventsListener::statusChanged (FeatureStateEvent const & a_featureStateEvent) {
				cout << "### 'UnoDispatchCommandEventsListener::statusChanged (FeatureStateEvent const & a_featureStateEvent)' is called." << endl << flush;
			}
			
			void UnoDispatchCommandEventsListener::disposing (::com::sun::star::lang::EventObject const & a_source) {
				cout << "### 'UnoDispatchCommandEventsListener::disposing (::com::sun::star::lang::EventObject const & a_source)' is called." << endl << flush;
			}
			
			void UnoDispatchCommandEventsListener::dispose () {
				cout << "### 'UnoDispatchCommandEventsListener::dispose ()' is called." << endl << flush;
				::com::sun::star::lang::EventObject l_event;
				l_event.Source = Reference <UnoDispatchCommandEventsListener> (this);
				for (Reference <XEventListener> const & l_eventsListener: i_eventsListeners) {
					l_eventsListener->disposing (l_event);
					i_eventsListeners.erase (l_eventsListener);
				}
			}
			
			void UnoDispatchCommandEventsListener::addEventListener (Reference <XEventListener> const & a_eventsListener) {
				cout << "### 'UnoDispatchCommandEventsListener::addEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.insert (a_eventsListener);
			}
			
			void UnoDispatchCommandEventsListener::removeEventListener (Reference <XEventListener> const & a_eventsListener) {
ut << "### 'UnoDispatchCommandEventsListener::removeEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.erase (a_eventsListener);
			}
			
			void UnoDispatchCommandEventsListener::additionalMethod () {
				cout << "### 'UnoDispatchCommandEventsListener::addtionalMethod ()' is called." << endl << flush;
			}

	#include <com/sun/star/lang/XEventListener.hpp>
	#include <cppuhelper/compbase1.hxx>
	#include "theBiasPlanet/unoUtilities/unoComponentBases/UnoComponentBase.hpp"
	
	using namespace ::cppu;
	using namespace ::theBiasPlanet::unoUtilities::unoComponentBases;
	
				class UnoGeneralEventsListener: public ImplInheritanceHelper1 <UnoComponentBase, ::com::sun::star::lang::XEventListener> {
					public:
						UnoGeneralEventsListener ();
						virtual ~UnoGeneralEventsListener ();
						virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_event) override;
				};

#include <iostream>

using namespace ::std;

			UnoGeneralEventsListener::UnoGeneralEventsListener (): ImplInheritanceHelper1 <UnoComponentBase, ::com::sun::star::lang::XEventListener> (string ("::theBiasPlanet::unoUtilities::localUnoObjectsTest1::UnoGeneralEventsListener")) {
				cout << "### 'UnoGeneralEventsListener::UnoGeneralEventsListener ()' is called." << endl << flush;
			}
			
			UnoGeneralEventsListener::~UnoGeneralEventsListener () {
				cout << "### 'UnoGeneralEventsListener::~UnoGeneralEventsListener ()' is called." << endl << flush;
			}
			
			void SAL_CALL UnoGeneralEventsListener::disposing (::com::sun::star::lang::EventObject const & a_event) {
				cout << "### 'UnoGeneralEventsListener::disposing (::com::sun::star::lang::EventObject const & a_event)' is called." << endl << flush;
			}
		}


Hypothesizer 7
I understand.

Objector 45A
What do you understand?

Hypothesizer 7
You should not define the UNO components that way, if you are going to use them your way.

Objector 45A
I have defined them according to your instruction . . .

Hypothesizer 7
They are not meant to be instantiated in the stack.

Objector 45A
You said that creating a local UNO object in the stack was "Not necessarily" wrong . . .

Hypothesizer 7
Certainly.

Objector 45A
"Certainly"? Just "Certainly"?

Hypothesizer 7
Well, did you read the article carefully?

Objector 45A
Of course not! Who does?

Hypothesizer 7
. . . The C++ UNO garbage collection mechanism is explained there, because that is a premise of the story.

Objector 45A
Damn the premise! Then, I will create the local UNO object in the heap, like this, also which causes a segmentation fault error!

Stage Direction
Objector 45A shows a piece of his code on the screen. Hypothesizer 7 surveys the piece.

@C++ Source Code
					UnoDispatchCommandEventsListener * l_unoDispatchCommandEventsListener (new UnoDispatchCommandEventsListener ());
					UnoGeneralEventsListener * l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					
					l_unoDispatchCommandEventsListener->addEventListener (l_unoGeneralEventsListener);
					l_unoDispatcher->addStatusListener (l_unoDispatchCommandEventsListener, *l_urlInURL);
					cout << "### dispatchWithNotification  () is being called." << endl << flush;
					l_unoDispatcher->dispatchWithNotification (*l_urlInURL, l_unoDispatchArgumentPropertiesSequence, l_unoDispatchCommandEventsListener);
					cout << "### dispatchWithNotification  () has returned." << endl << flush;
					l_unoDispatcher->removeStatusListener (l_unoDispatchCommandEventsListener, *l_urlInURL);
					l_unoDispatchCommandEventsListener->additionalMethod ();
					l_unoDispatchCommandEventsListener->dispose ();
					delete l_unoGeneralEventsListener;
					delete l_unoDispatchCommandEventsListener;

Hypothesizer 7
. . . You do not really understand the C++ UNO garbage collection mechanism, do you?

Stage Direction
Objector 45A curses and reads the description on the C++ UNO garbage collection mechanism, very grudgingly.

Objector 45A
. . . OK, now, I understand why my pieces of code don't work: as for the local UNO objects in the stack, the C++ UNO garbage collection mechanism tries to delete the local UNO objects, but cannot delete the objects in the stack, right?

Hypothesizer 7
Well, that is, certainly, a part of the story . . .

Objector 45A
So, this should work!

Stage Direction
Objector 45A creates some not-garbage-collected versions of the UNO components.

@C++ Source Code
	#include <cppuhelper/compbase1.hxx>
	#include <com/sun/star/lang/XUnoTunnel.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	
				class NotGarbageCollectedUnoComponentBaseAttempt: public WeakImplHelper1 <XUnoTunnel> {
					protected:
						string const i_unoComponentName;
					public:
						NotGarbageCollectedUnoComponentBaseAttempt (string const & a_unoComponentName);
						virtual ~NotGarbageCollectedUnoComponentBaseAttempt ();
						virtual void SAL_CALL acquire () throw () override;
						virtual void SAL_CALL release () throw () override;
						virtual sal_Int64 SAL_CALL getSomething (Sequence <sal_Int8> const & a_datumIdentification) override;
				};

#include <iostream>

			NotGarbageCollectedUnoComponentBaseAttempt::NotGarbageCollectedUnoComponentBaseAttempt (string const & a_unoComponentName): WeakImplHelper1 <XUnoTunnel> (), i_unoComponentName (a_unoComponentName) {
				cout << "### 'NotGarbageCollectedUnoComponentBaseAttempt::NotGarbageCollectedUnoComponentBaseAttempt ()' is called." << endl << flush;
			}
			
			NotGarbageCollectedUnoComponentBaseAttempt::~NotGarbageCollectedUnoComponentBaseAttempt () {
				cout << "### 'NotGarbageCollectedUnoComponentBaseAttempt::~NotGarbageCollectedUnoComponentBaseAttempt ()' is called." << endl << flush;
			}
			
			void SAL_CALL NotGarbageCollectedUnoComponentBaseAttempt::acquire () throw () {
				cout << "### 'NotGarbageCollectedUnoComponentBaseAttempt::acquire ()' is called." << endl << flush;
			}
			
			void SAL_CALL NotGarbageCollectedUnoComponentBaseAttempt::release () throw () {
				cout << "### 'NotGarbageCollectedUnoComponentBaseAttempt::release ()' is called." << endl << flush;
			}
			
			sal_Int64 SAL_CALL NotGarbageCollectedUnoComponentBaseAttempt::getSomething (Sequence <sal_Int8> const & a_datumIdentification) {
				return (sal_Int64) this;
			}

	#include <set>
	#include <com/sun/star/frame/FeatureStateEvent.hpp>
	#include <com/sun/star/frame/XDispatchResultListener.hpp>
	#include <com/sun/star/frame/XStatusListener.hpp>
	#include <com/sun/star/lang/XComponent.hpp>
	#include <com/sun/star/lang/XEventListener.hpp>
	#include <com/sun/star/uno/Reference.hxx>
	#include <cppuhelper/compbase3.hxx>
	#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/NotGarbageCollectedUnoComponentBaseAttempt.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::frame;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	
				class NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt: public ImplInheritanceHelper3 <NotGarbageCollectedUnoComponentBaseAttempt, XComponent, XDispatchResultListener, XStatusListener> {
					private:
						set <Reference <::com::sun::star::lang::XEventListener>> i_eventsListeners;
					public:
						NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt ();
						virtual ~NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt ();
						virtual void SAL_CALL dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) override;
						virtual void SAL_CALL statusChanged (FeatureStateEvent const & a_featureStateEvent) override;
						virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_source) override;
						virtual void SAL_CALL dispose () override;
						virtual void SAL_CALL addEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual void SAL_CALL removeEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual void additionalMethod ();
				};

#include <iostream>

			NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt (): ImplInheritanceHelper3 <NotGarbageCollectedUnoComponentBaseAttempt, XComponent, XDispatchResultListener, XStatusListener> (string ("::theBiasPlanet::unoUtilitiesTests::localUnoObjectsTest1::NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt")) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt ()' is called." << endl << flush;
			}
			
			NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::~NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt () {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::~NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt ()' is called." << endl << flush;
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent)' is called." << endl << flush;
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::statusChanged (FeatureStateEvent const & a_featureStateEvent) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::statusChanged (FeatureStateEvent const & a_featureStateEvent)' is called." << endl << flush;
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::disposing (::com::sun::star::lang::EventObject const & a_source) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::disposing (::com::sun::star::lang::EventObject const & a_source)' is called." << endl << flush;
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::dispose () {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::dispose ()' is called." << endl << flush;
				::com::sun::star::lang::EventObject l_event;
				l_event.Source = Reference <NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt> (this);
				for (Reference <XEventListener> const & l_eventsListener: i_eventsListeners) {
					l_eventsListener->disposing (l_event);
					i_eventsListeners.erase (l_eventsListener);
				}
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::addEventListener (Reference <XEventListener> const & a_eventsListener) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::addEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.insert (a_eventsListener);
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::removeEventListener (Reference <XEventListener> const & a_eventsListener) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::removeEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.erase (a_eventsListener);
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::additionalMethod () {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListenerAttempt::addtionalMethod ()' is called." << endl << flush;
			}

* The code for 'NotGarbageCollectedUnoGeneralEventsListenerAttempt' is omitted here.

Hypothesizer 7
. . . I see your point, but . . .

Objector 45A
I have eliminated the automatic destruction of the UNO object by overriding the 'release ()' method, an ingenious idea!

Hypothesizer 7
Well . . .

Stage Direction
Objector 45A executes the modified version of his stack-based program, which causes a segmentation fault error.

Objector 45A
Huh? Impossible!

Hypothesizer 7
In fact, it is very possible, although your program may succeed occasionally, by luck.

I warn you that your heap-based program will be no better.


2: The Usage Count Is Usually Decremented Delayedly


Hypothesizer 7
You should understand that the usage count is usually decremented delayedly.

Objector 45A
Huh? What do you mean by "delayedly"?

Hypothesizer 7
For example, in your code, the usage count of 'l_unoDispatchCommandEventsListener' does not usually return to the previous number immediately after the 'dispatchWithNotification' method has returned.

Objector 45A
. . . Then, when does it return to the previous number?

Hypothesizer 7
Eventually.

Objector 45A
"Eventually" is a vague word. . . . But anyway, so what? As my UNO components don't use the usage counts at all, whenever the usage counts are decremented, it doesn't matter, right?

Hypothesizer 7
It matters, actually. Regardless of the behavior of your UNO component, the UNO server (the LibreOffice or Apache OpenOffice instance) persists to try to decrement the usage count; if your UNO object has been already disposed, that will cause a segmentation error.

Objector 45A
Ah, sure. . . . So, my program can just sleep until the usage count is decremented to '0' . . . eventually?

Hypothesizer 7
It could, but you do not want to make the UNO component periodically poll the usage count, do you?

Objector 45A
Well, I don't particularly want to, but if I have to . . .

Hypothesizer 7
If you persist to outsmart the C++ UNO garbage collection mechanism, this may be a better solution, which I do not particularly recommend.

Stage Direction
Hypothesizer 7 creates his own not-garbage-collected versions of the UNO components.

@C++ Source Code
	#include <condition_variable>
	#include <mutex>
	#include <cppuhelper/compbase1.hxx>
	#include <com/sun/star/lang/XUnoTunnel.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	
	using namespace ::std;
<codeLine><![CDATA[	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	
				class NotGarbageCollectedUnoComponentBase: public WeakImplHelper1 <XUnoTunnel> {
					protected:
						recursive_mutex i_mutex;
						condition_variable_any i_threadCondition;
						string const i_unoComponentName;
						virtual void waitForBeingReleased ();
					public:
						NotGarbageCollectedUnoComponentBase (string const & a_unoComponentName);
						virtual ~NotGarbageCollectedUnoComponentBase ();
						virtual void SAL_CALL acquire () throw () override;
						virtual void SAL_CALL release () throw () override;
						virtual sal_Int64 SAL_CALL getSomething (Sequence <sal_Int8> const & a_datumIdentification) override;
				};

#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/NotGarbageCollectedUnoComponentBase.hpp"
#include <iostream>

			void NotGarbageCollectedUnoComponentBase::waitForBeingReleased () {
				unique_lock <recursive_mutex> l_lock (i_mutex);
				cout << "### 'NotGarbageCollectedUnoComponentBase::waitForBeingReleased ()' is called." << endl << flush;
				while (true) {
					if (m_refCount > 0) {
						cout << "### waiting for '" << m_refCount << "' pointers to release this." << endl << flush;
						i_threadCondition.wait (l_lock);
					}
					else {
						break;
					}
				}
				cout << "### 'NotGarbageCollectedUnoComponentBase::waitForBeingReleased ()' is ending." << endl << flush;
			}
			
			NotGarbageCollectedUnoComponentBase::NotGarbageCollectedUnoComponentBase (string const & a_unoComponentName): WeakImplHelper1 <XUnoTunnel> (), i_unoComponentName (a_unoComponentName) {
				cout << "### 'NotGarbageCollectedUnoComponentBase::NotGarbageCollectedUnoComponentBase ()' is called." << endl << flush;
			}
			
			NotGarbageCollectedUnoComponentBase::~NotGarbageCollectedUnoComponentBase () {
				cout << "### 'NotGarbageCollectedUnoComponentBase::~NotGarbageCollectedUnoComponentBase ()' is called." << endl << flush;
			}
			
			void SAL_CALL NotGarbageCollectedUnoComponentBase::acquire () throw () {
				unique_lock <recursive_mutex> l_lock (i_mutex);
				m_refCount ++;
				cout << "### The usage count of a '" << i_unoComponentName << "' instance has been incremented to '" << m_refCount << "'." << endl << flush;
			}
			
			void SAL_CALL NotGarbageCollectedUnoComponentBase::release () throw () {
				unique_lock <recursive_mutex> l_lock (i_mutex);
				m_refCount --;
				cout << "### The usage count of a '" << i_unoComponentName << "' instance has been decremented to '" << m_refCount << "'." << endl << flush;
				if (m_refCount <= 0) {
					cout << "### notifying the destructor thread, if any." << endl << flush;
					i_threadCondition.notify_all ();
				}
			}
			
			sal_Int64 SAL_CALL NotGarbageCollectedUnoComponentBase::getSomething (Sequence <sal_Int8> const & a_datumIdentification) {
				return (sal_Int64) this;
			}

	#include <set>
	#include <com/sun/star/frame/FeatureStateEvent.hpp>
	#include <com/sun/star/frame/XDispatchResultListener.hpp>
	#include <com/sun/star/frame/XStatusListener.hpp>
	#include <com/sun/star/lang/XComponent.hpp>
	#include <com/sun/star/lang/XEventListener.hpp>
	#include <com/sun/star/uno/Reference.hxx>
	#include <cppuhelper/compbase3.hxx>
	#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/NotGarbageCollectedUnoComponentBase.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::frame;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	
				class NotGarbageCollectedUnoDispatchCommandEventsListener: public ImplInheritanceHelper3 <NotGarbageCollectedUnoComponentBase, XComponent, XDispatchResultListener, XStatusListener> {
					private:
						set <Reference <::com::sun::star::lang::XEventListener>> i_eventsListeners;
					public:
						NotGarbageCollectedUnoDispatchCommandEventsListener ();
						virtual ~NotGarbageCollectedUnoDispatchCommandEventsListener ();
						virtual void SAL_CALL dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) override;
						virtual void SAL_CALL statusChanged (FeatureStateEvent const & a_featureStateEvent) override;
						virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_source) override;
						virtual void SAL_CALL dispose () override;
						virtual void SAL_CALL addEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual void SAL_CALL removeEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual void additionalMethod ();
				};

#include <iostream>

			NotGarbageCollectedUnoDispatchCommandEventsListener::NotGarbageCollectedUnoDispatchCommandEventsListener (): ImplInheritanceHelper3 <NotGarbageCollectedUnoComponentBase, XComponent, XDispatchResultListener, XStatusListener> (string ("::theBiasPlanet::unoUtilitiesTests::localUnoObjectsTest1::NotGarbageCollectedUnoDispatchCommandEventsListener")) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::NotGarbageCollectedUnoDispatchCommandEventsListener ()' is called." << endl << flush;
			}
			
			NotGarbageCollectedUnoDispatchCommandEventsListener::~NotGarbageCollectedUnoDispatchCommandEventsListener () {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::~NotGarbageCollectedUnoDispatchCommandEventsListener ()' is called." << endl << flush;
				waitForBeingReleased ();
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListener::dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::dispatchFinished (DispatchResultEvent const & a_dispatchResultEvent)' is called." << endl << flush;
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListener::statusChanged (FeatureStateEvent const & a_featureStateEvent) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::statusChanged (FeatureStateEvent const & a_featureStateEvent)' is called." << endl << flush;
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListener::disposing (::com::sun::star::lang::EventObject const & a_source) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::disposing (::com::sun::star::lang::EventObject const & a_source)' is called." << endl << flush;
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListener::dispose () {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::dispose ()' is called." << endl << flush;
				::com::sun::star::lang::EventObject l_event;
				l_event.Source = Reference <NotGarbageCollectedUnoDispatchCommandEventsListener> (this);
				for (Reference <XEventListener> const & l_eventsListener: i_eventsListeners) {
					l_eventsListener->disposing (l_event);
					i_eventsListeners.erase (l_eventsListener);
				}
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListener::addEventListener (Reference <XEventListener> const & a_eventsListener) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::addEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.insert (a_eventsListener);
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListener::removeEventListener (Reference <XEventListener> const & a_eventsListener) {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::removeEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.erase (a_eventsListener);
			}
			
			void NotGarbageCollectedUnoDispatchCommandEventsListener::additionalMethod () {
				cout << "### 'NotGarbageCollectedUnoDispatchCommandEventsListener::addtionalMethod ()' is called." << endl << flush;
			}

* The code for 'NotGarbageCollectedUnoGeneralEventsListener' is omitted here.

Objector 45A
. . . So, the UNO object notifies itself when the usage count has been decremented to '0'.

Hypothesizer 7
If you use the UNO component, the output will show that the usage count tends to be decremented after the destructor is called.

Objector 45A
Well, as you say "Eventually", can't the destruction be suspended indefinitely?

Hypothesizer 7
A good point. Strictly speaking, there is no guarantee that the UNO object is not kept held indefinitely, but practically speaking, I do not think that the local UNO object will be kept held for a long time without any specific reason.

Objector 45A
Why don't you "particularly recommend" it?

Hypothesizer 7
I would rather go with the C++ UNO garbage collection mechanism than outsmart it.

Objector 45A
But I want to control when my UNO objects demise!.

Hypothesizer 7
I understand that sentiment very well, really, but that non-guaranteed-ness deters me.


3: When an Automatic Conversions to a '::com::sun::star::uno::Reference' Instance Happens


Objector 45A
So, supposing that I go with the original definition of the UNO component, should I do like this?

Stage Direction
Objector 45A modifies his program on the screen.

@C++ Source Code
					UnoDispatchCommandEventsListener * l_unoDispatchCommandEventsListener (new UnoDispatchCommandEventsListener ());
					l_unoDispatchCommandEventsListener->acquire ();
					UnoGeneralEventsListener * l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					l_unoGeneralEventsListener->acquire ();
					
					l_unoDispatchCommandEventsListener->addEventListener (l_unoGeneralEventsListener);
					l_unoDispatcher->addStatusListener (l_unoDispatchCommandEventsListener, *l_urlInURL);
					cout << "### dispatchWithNotification  () is being called." << endl << flush;
					l_unoDispatcher->dispatchWithNotification (*l_urlInURL, l_unoDispatchArgumentPropertiesSequence, l_unoDispatchCommandEventsListener);
					cout << "### dispatchWithNotification  () has returned." << endl << flush;
					l_unoDispatcher->removeStatusListener (l_unoDispatchCommandEventsListener, *l_urlInURL);
					l_unoDispatchCommandEventsListener->additionalMethod ();
					l_unoDispatchCommandEventsListener->dispose ();
					l_unoGeneralEventsListener->release ();
					l_unoDispatchCommandEventsListener->release ();

Hypothesizer 7
. . . Hmm . . .

Objector 45A
What?

Hypothesizer 7
Are you aware of those automatic conversions?

Objector 45A
"those"? Which?

Hypothesizer 7
The conversion of 'l_unoGeneralEventsListener' to a '::com::sun::star::uno::Reference <::com::sun::star::lang::XEventListener>' instance for the call of 'l_unoDispatchCommandEventsListener->addEventListener', the conversion of 'l_unoDispatchCommandEventsListener' to a '::com::sun::star::uno::Reference <::com::sun::star::frame::XStatusListener>' instance for the call of 'l_unoDispatcher->addStatusListener', the conversion of 'l_unoDispatchCommandEventsListener' to a '::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>' instance for the call of 'l_unoDispatcher->dispatchWithNotification', and the conversion of 'l_unoDispatchCommandEventsListener' to a '::com::sun::star::uno::Reference <::com::sun::star::frame::XStatusListener>' instance for the call of 'l_unoDispatcher->removeStatusListener'. You know that each of those arguments is really of a '::com::sun::star::uno::Reference' type.

Objector 45A
. . . So what?

Hypothesizer 7
They are inefficient: a temporary '::com::sun::star::uno::Reference' instance is created for each call.

Objector 45A
Does that really matter? Being told "each call", it's only 4 calls . . .

Hypothesizer 7
If the function is called 1,000 times, it will be 4,000 calls.

Objector 45A
True, but still, I don't think that it practically matters.

Hypothesizer 7
Depending on your program, it may be so. . . . Nevertheless, I would not dare to write obviously inefficient code.

Objector 45A
Oh? Then, what would be your code?

Hypothesizer 7
This is crude, but will be better.

Stage Direction
Hypothesizer 7 writes his version on the screen.

@C++ Source Code
					UnoDispatchCommandEventsListener * l_unoDispatchCommandEventsListener (new UnoDispatchCommandEventsListener ());
					l_unoDispatchCommandEventsListener->acquire ();
					UnoGeneralEventsListener * l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					l_unoGeneralEventsListener->acquire ();
					
					Reference <XDispatchResultListener> l_unoDispatchCommandEventsListenerInXDispatchResultListener (l_unoDispatchCommandEventsListener);
					Reference <XStatusListener> l_unoDispatchCommandEventsListenerInXStatusListener (l_unoDispatchCommandEventsListener);
					Reference <::com::sun::star::lang::XEventListener> l_unoGeneralEventsListenerInXEventListener (l_unoGeneralEventsListener);
					l_unoDispatchCommandEventsListener->addEventListener (l_unoGeneralEventsListenerInXEventListener);
					l_unoDispatcher->addStatusListener (l_unoDispatchCommandEventsListenerInXStatusListener, *l_urlInURL);
					cout << "### dispatchWithNotification  () is being called." << endl << flush;
					l_unoDispatcher->dispatchWithNotification (*l_urlInURL, l_unoDispatchArgumentPropertiesSequence, l_unoDispatchCommandEventsListenerInXDispatchResultListener);
					cout << "### dispatchWithNotification  () has returned." << endl << flush;
					l_unoDispatcher->removeStatusListener (l_unoDispatchCommandEventsListenerInXStatusListener, *l_urlInURL);
					l_unoDispatchCommandEventsListener->additionalMethod ();
					l_unoDispatchCommandEventsListener->dispose ();
					l_unoGeneralEventsListener->release ();
					l_unoDispatchCommandEventsListener->release ();

Objector 45A
Yuck! That looks ugly!

Hypothesizer 7
Well, I do not share your sense of "ugl"iness. . . . Your version is just hiding ugly conversions; certainly, they are hidden, but they are there nonetheless, and I sense the ugliness even more because it is hidden.

Objector 45A
My version is much shorter!

Hypothesizer 7
The shortness of source code does not positively correlate with the efficiency or the readability of the code, which is more important, in my opinion.

Objector 45A
My version is obviously neater!

Hypothesizer 7
I do not value such "neat"ness. Such neatness is just a cosmetic, which can deceive only people who cannot see through the surface.

Objector 45A
. . . Your version is no-good, because this eliminates automatic conversions, but is neater because 'acquire' and 'release' are eliminated!

Stage Direction
Objector 45A modifies his program on the screen.

@C++ Source Code
					Reference <UnoDispatchCommandEventsListener> l_unoDispatchCommandEventsListener (new UnoDispatchCommandEventsListener ());
					Reference <UnoGeneralEventsListener> l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					
					l_unoDispatchCommandEventsListener->addEventListener (l_unoGeneralEventsListener);
					l_unoDispatcher->addStatusListener (l_unoDispatchCommandEventsListener, *l_urlInURL);
					cout << "### dispatchWithNotification  () is being called." << endl << flush;
					l_unoDispatcher->dispatchWithNotification (*l_urlInURL, l_unoDispatchArgumentPropertiesSequence, l_unoDispatchCommandEventsListener);
					cout << "### dispatchWithNotification  () has returned." << endl << flush;
					l_unoDispatcher->removeStatusListener (l_unoDispatchCommandEventsListener, *l_urlInURL);
					l_unoDispatchCommandEventsListener->additionalMethod ();
					l_unoDispatchCommandEventsListener->dispose ();


Hypothesizer 7
. . . You know, that does not eliminate the automatic conversions.

Objector 45A
Huh? Why?

Hypothesizer 7
You know, any class template is not so-called "covariant" or so-called "contravariant".

Objector 45A
Which means?

Hypothesizer 7
'::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>' is not in the is-a relationship with '::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>', etc.; so, any '::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>' instance cannot pass as a '::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>', etc. instance.

Objector 45A
Why?

Hypothesizer 7
'::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>' means that its instance can contain any 'UnoDispatchCommandEventsListener' UNO object or UNO proxy address, but can contain only a 'UnoDispatchCommandEventsListener' UNO object or UNO proxy address, which does not satisfy the definition of '::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>'.

Objector 45A
Doesn't it?

Hypothesizer 7
Anything that can contain only a 'UnoDispatchCommandEventsListener' UNO object or UNO proxy address is not something that can contain any '::com::sun::star::frame::XDispatchResultListener' UNO object or UNO proxy address, which is an imperative part of the definition of '::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>'. . . . The logic is the same with the one described for Java arrays.

Objector 45A
. . . Strictly speaking, that may be so . . .

Hypothesizer 7
It should be always strictly spoken, sir. . . . If a '::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>' instance could be passed into a '::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener> &' argument, the function would try to put a '::com::sun::star::frame::XDispatchResultListener' (but not any 'UnoDispatchCommandEventsListener') instance address into it, which would be a trouble.

Objector 45A
. . . There may be such a case, but . . .

Hypothesizer 7
You know, preventing such troubles is the point of being a statically typed programming language.

Objector 45A
Whatever . . .

Objector 45B
You have been talking about local UNO objects, but as for any remote UNO object, I cannot even use automatic conversions, even if I am willing to accept "ugly" inefficiencies, right?

Hypothesizer 7
Madam, any automatic conversion to a '::com::sun::star::uno::Reference' instance can happen only when 1) the source is an address of the destination template type or its sub class, for example, the source is a '::com::sun::star::frame::XDesktop2 *' address and the destination is '::com::sun::star::uno::Reference <::com::sun::star::frame::XDesktop> &' or 2) the source is a '::com::sun::star::uno::Reference' instance of a template type of a sub class of the destination template type, for example, the source is a '::com::sun::star::uno::Reference <::com::sun::star::frame::XDesktop2>' instance and the destination is '::com::sun::star::uno::Reference <::com::sun::star::frame::XDesktop> &'.

Objector 45B
Um? Ah. So, only in some cases, an automatic conversion may happen for a remote UNO object.


4: How to Manage Any UNO Object Handily


Objector 45B
Anyway, it is cumbersome to have to create multiple 'Reference' instances for different template types for one UNO object.

Hypothesizer 7
I understand.

Objector 45B
. . . It's the pain in the neck in UNO programming.

Hypothesizer 7
I understand.

Objector 45B
. . . Is that all you can say? "I understand"?

Hypothesizer 7
I can say that a smart pointer may be helpful.

Objector 45B
What do you mean by "a smart pointer"?

Hypothesizer 7
I mean this.

Stage Direction
Hypothesizer 7 shows his smart pointer code on the screen.

UnoObjectPointer.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilities_pointers_UnoObjectPointer_hpp__
	#define __theBiasPlanet_unoUtilities_pointers_UnoObjectPointer_hpp__
	
	#include <map>
	#include <string>
	#include <com/sun/star/uno/Reference.hxx>
	#include "theBiasPlanet/unoUtilities/visualCplusplusSpecificHeaders/VisualCplusplusSpecificDefinitions.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::uno;
	
	namespace theBiasPlanet {
		namespace unoUtilities {
			namespace pointers {
				template <typename T> class __theBiasPlanet_unoUtilities_symbolExportingOrImportingForVisualCplusplus__ UnoObjectPointer {
					private:
						T * i_primaryAddress = nullptr;
						map <string const, void * const> i_unoInterfaceNameToPointerInReferenceMap;
						virtual void initialize ();
					public:
						UnoObjectPointer ();
						UnoObjectPointer (T * const a_primaryAddress);
						UnoObjectPointer (Reference <T> const & a_primaryAddressPointer);
						template <typename U> UnoObjectPointer (Reference <U> const & a_sourcePointer, bool const & a_targetAddressIsQueried = false, typename enable_if <!is_same <T, U>::value>::type * a_dummy = nullptr);
						template <typename U> UnoObjectPointer (UnoObjectPointer <U> & a_sourcePointer, bool const & a_targetAddressIsQueried = false, typename enable_if <!is_same <T, U>::value>::type * a_dummy = nullptr);
						template <typename U> UnoObjectPointer (UnoObjectPointer <U> && a_sourcePointer, bool const & a_targetAddressIsQueried = false, typename enable_if <!is_same <T, U>::value>::type * a_dummy = nullptr);
						UnoObjectPointer (UnoObjectPointer <T> const & a_sourcePointer);
						UnoObjectPointer <T> & operator = (UnoObjectPointer <T> const & a_sourcePointer);
						virtual ~UnoObjectPointer ();
						virtual bool isEmpty ();
						virtual void setPrimaryAddress (T * const a_primaryAddress);
						virtual void setPrimaryAddress (Reference <T> const & a_primaryAddressPointer);
						template <typename U> void setPrimaryAddress (Reference <U> const & a_sourcePointer, bool const & a_targetAddressIsQueried = false, typename enable_if <!is_same <T, U>::value>::type * a_dummy = nullptr);
						template <typename U> void setPrimaryAddress (UnoObjectPointer <U> & a_sourcePointer, bool const & a_targetAddressIsQueried = false, typename enable_if <!is_same <T, U>::value>::type * a_dummy = nullptr);
						template <typename U> void setPrimaryAddress (UnoObjectPointer <U> && a_sourcePointer, bool const & a_targetAddressIsQueried = false, typename enable_if <!is_same <T, U>::value>::type * a_dummy = nullptr);
						virtual void clear ();
						virtual T & operator * ();
						virtual T * const operator -> ();
						virtual Reference <T> & getPointerInReference ();
						template <typename U> Reference <U> & getPointerInReference (bool const & a_pointerIsQueried = false, typename enable_if <!is_same <T, U>::value>::type * a_dummy = nullptr);
				};
			}
		}
	}
#endif

UnoObjectPointer.tpp

@C++ Source Code
#include "theBiasPlanet/unoUtilities/pointers/UnoObjectPointer.hpp"
#include <com/sun/star/uno/XInterface.hpp>
#include "theBiasPlanet/coreUtilities/messagingHandling/Publisher.hpp"

using namespace ::theBiasPlanet::coreUtilities::messagingHandling;

namespace theBiasPlanet {
	namespace unoUtilities {
		namespace pointers {
			template <typename T> void UnoObjectPointer <T>::initialize () {
				if (i_primaryAddress != nullptr) {
					Publisher::logDebugInformation ("### An instance of 'UnoObjectPointer' is being initialized.");
					i_primaryAddress->acquire ();
				}
			}
			
			template <typename T> UnoObjectPointer <T>::UnoObjectPointer () {
			}
			
			template <typename T> UnoObjectPointer <T>::UnoObjectPointer (T * const a_primaryAddress): i_primaryAddress (a_primaryAddress) {
				initialize ();
			}
			
			template <typename T> UnoObjectPointer <T>::UnoObjectPointer (Reference <T> const & a_primaryAddressPointer): UnoObjectPointer (a_primaryAddressPointer.get ()) {
			}
			
			template <typename T> template <typename U> UnoObjectPointer <T>::UnoObjectPointer (Reference <U> const & a_sourcePointer, bool const & a_targetAddressIsQueried, typename enable_if <!is_same <T, U>::value>::type * a_dummy): UnoObjectPointer <T> (!a_targetAddressIsQueried ? Reference <T> (a_sourcePointer): Reference <T> (a_sourcePointer, UNO_QUERY)) {
			}
			
			// Only the primary address is set.
			template <typename T> template <typename U> UnoObjectPointer <T>::UnoObjectPointer (UnoObjectPointer <U> & a_sourcePointer, bool const & a_targetAddressIsQueried, typename enable_if <!is_same <T, U>::value>::type * a_dummy): UnoObjectPointer <T> (a_sourcePointer.template getPointerInReference <T> (a_targetAddressIsQueried)) {
			}
			
			// Only the primary address is set.
			template <typename T> template <typename U> UnoObjectPointer <T>::UnoObjectPointer (UnoObjectPointer <U> && a_sourcePointer, bool const & a_targetAddressIsQueried, typename enable_if <!is_same <T, U>::value>::type * a_dummy): UnoObjectPointer <T> (a_sourcePointer.template getPointerInReference <T> (a_targetAddressIsQueried)) {
			}
			
			// Only the primary address is copied.
			template <typename T> UnoObjectPointer <T>::UnoObjectPointer (UnoObjectPointer <T> const & a_sourcePointer): i_primaryAddress (a_sourcePointer.i_primaryAddress) {
				Publisher::logDebugInformation ("### An instance of 'UnoObjectPointer' is being copied.");
				initialize ();
			}
			
			// Only the primary address is copied.
			template <typename T> UnoObjectPointer <T> & UnoObjectPointer <T>::operator = (UnoObjectPointer <T> const & a_sourcePointer) {
				Publisher::logDebugInformation ("### An instance of 'UnoObjectPointer' is being assigned.");
				clear ();
				i_primaryAddress = a_sourcePointer.i_primaryAddress;
				initialize ();
				return *this;
			}
			
			template <typename T> UnoObjectPointer <T>::~UnoObjectPointer () {
				clear ();
			}
			
			template <typename T> bool UnoObjectPointer <T>::isEmpty () {
				return i_primaryAddress == nullptr;
			}
			
			template <typename T> void UnoObjectPointer <T>::setPrimaryAddress (T * const a_primaryAddress) {
				clear ();
				i_primaryAddress = a_primaryAddress;
				initialize ();
			}
			
			template <typename T> void UnoObjectPointer <T>::setPrimaryAddress (Reference <T> const & a_primaryAddressPointer) {
				clear ();
				i_primaryAddress = a_primaryAddressPointer.get ();
				initialize ();
			}
			
			template <typename T> template <typename U>  void UnoObjectPointer <T>::setPrimaryAddress (Reference <U> const & a_sourcePointer, bool const & a_targetAddressIsQueried, typename enable_if <!is_same <T, U>::value>::type * a_dummy) {
				setPrimaryAddress (!a_targetAddressIsQueried ? Reference <T> (a_sourcePointer): Reference <T> (a_sourcePointer, UNO_QUERY));
			}
			
			template <typename T> template <typename U> void UnoObjectPointer <T>::setPrimaryAddress (UnoObjectPointer <U> & a_sourcePointer, bool const & a_targetAddressIsQueried, typename enable_if <!is_same <T, U>::value>::type * a_dummy) {
				setPrimaryAddress (a_sourcePointer.template getPointerInReference <T> (a_targetAddressIsQueried));
			}
			
			template <typename T> template <typename U> void UnoObjectPointer <T>::setPrimaryAddress (UnoObjectPointer <U> && a_sourcePointer, bool const & a_targetAddressIsQueried, typename enable_if <!is_same <T, U>::value>::type * a_dummy) {
				setPrimaryAddress (a_sourcePointer.template getPointerInReference <T> (a_targetAddressIsQueried));
			}
			
			template <typename T> void UnoObjectPointer <T>::clear () {
				if (i_primaryAddress != nullptr) {
					Publisher::logDebugInformation ("### An instance of 'UnoObjectPointer' is being cleared.");
					i_primaryAddress->release ();
					map <string const, void * const>::iterator l_unoInterfaceNameToPointerInReferenceMapIterator (i_unoInterfaceNameToPointerInReferenceMap.begin ());
					map <string const, void * const>::iterator l_unoInterfaceNameToPointerInReferenceMapIteratorAtEnd (i_unoInterfaceNameToPointerInReferenceMap.end ());
					for (; l_unoInterfaceNameToPointerInReferenceMapIterator != l_unoInterfaceNameToPointerInReferenceMapIteratorAtEnd;) {
						string l_unoInterfaceName (l_unoInterfaceNameToPointerInReferenceMapIterator->first);
						// * In fact, it isn't 'Reference <XInterface> *', but practically, that doesn't seem to matter; if it turns out to matter, the address will have to be cast to the correct type.
						Publisher::logDebugInformation ("### An instance of 'Reference' in an instance of 'UnoObjectPointer' is being disposed.");
						delete (Reference <XInterface> *) (l_unoInterfaceNameToPointerInReferenceMapIterator->second);
						l_unoInterfaceNameToPointerInReferenceMapIterator = i_unoInterfaceNameToPointerInReferenceMap.erase (l_unoInterfaceNameToPointerInReferenceMapIterator);
					}
					i_primaryAddress = nullptr;
				}
			}
			
			template <typename T> T & UnoObjectPointer <T>::operator * () {
				return *i_primaryAddress;
			}
			
			template <typename T> T * const UnoObjectPointer <T>::operator -> () {
				return i_primaryAddress;
			}
			
			template <typename T> Reference <T> & UnoObjectPointer <T>::getPointerInReference () {
				void * l_pointerInReference = nullptr;
				string l_unoInterfaceName (typeid (T).name ());
				try {
					l_pointerInReference = i_unoInterfaceNameToPointerInReferenceMap.at (l_unoInterfaceName);
				}
				catch (out_of_range l_exception) {
					Publisher::logDebugInformation ("### An instance of 'Reference' in an instance of 'UnoObjectPointer' is being created.");
					l_pointerInReference = new Reference <T> ( (T *) i_primaryAddress);
					i_unoInterfaceNameToPointerInReferenceMap.insert ( {l_unoInterfaceName, l_pointerInReference});
				}
				return * ((Reference <T> *) l_pointerInReference);
			}
			
			template <typename T> template <typename U> Reference <U> & UnoObjectPointer <T>::getPointerInReference (bool const & a_pointerIsQueried, typename enable_if <!is_same <T, U>::value>::type * a_dummy) {
				void * l_pointerInReference = nullptr;
				string l_unoInterfaceName (typeid (U).name ());
				try {
					l_pointerInReference = i_unoInterfaceNameToPointerInReferenceMap.at (l_unoInterfaceName);
				}
				catch (out_of_range l_exception) {
					Publisher::logDebugInformation ("### An instance of 'Reference' in an instance of 'UnoObjectPointer' is being created.");
					if (!a_pointerIsQueried) {
						l_pointerInReference = new Reference <U> ( (U *) i_primaryAddress);
					}
					else {
						l_pointerInReference = new Reference <U> ( (U *) i_primaryAddress, UNO_QUERY);
					}
					i_unoInterfaceNameToPointerInReferenceMap.insert ( {l_unoInterfaceName, l_pointerInReference});
				}
				return * ((Reference <U> *) l_pointerInReference);
			}
		}
	}
}

Objector 45B
. . . Well, I don't know . . .

Hypothesizer 7
The smart pointer concentrates multiple '::com::sun::star::uno::Reference' instances for one UNO object in one place.

Objector 45B
How will it be used?

Hypothesizer 7
This is an example usage.

Stage Direction
Hypothesizer 7 shows his example code on the screen.

@C++ Source Code
					UnoObjectPointer <UnoDispatchCommandEventsListener> l_unoDispatchCommandEventsListener (new UnoDispatchCommandEventsListener ());
					UnoObjectPointer <UnoGeneralEventsListener> l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					
					l_unoDispatchCommandEventsListener->addEventListener (l_unoGeneralEventsListener.getPointerInReference <::com::sun::star::lang::XEventListener> ());
					l_unoDispatcher->addStatusListener (l_unoDispatchCommandEventsListener.getPointerInReference <XStatusListener> (), *l_urlInURL);
					cout << "### dispatchWithNotification  () is being called." << endl << flush;
					l_unoDispatcher->dispatchWithNotification (*l_urlInURL, l_unoDispatchArgumentPropertiesSequence, l_unoDispatchCommandEventsListener.getPointerInReference <XDispatchResultListener> ());
					cout << "### dispatchWithNotification  () has returned." << endl << flush;
					l_unoDispatcher->removeStatusListener (l_unoDispatchCommandEventsListener.getPointerInReference <XStatusListener> (), *l_urlInURL);
					l_unoDispatchCommandEventsListener->additionalMethod ();
					l_unoDispatchCommandEventsListener->dispose ();

Objector 45B
. . . I don't know how that is less cumbersome than this.

Stage Direction
Objector 45B writes her own example code on the screen.

@C++ Source Code
					Reference <UnoDispatchCommandEventsListener> l_unoDispatchCommandEventsListener (new UnoDispatchCommandEventsListener ());
					Reference <UnoGeneralEventsListener> l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					
					l_unoDispatchCommandEventsListener->addEventListener (Reference <::com::sun::star::lang::XEventListener> (l_unoGeneralEventsListener));
					l_unoDispatcher->addStatusListener (Reference <XStatusListener> (l_unoDispatchCommandEventsListener), *l_urlInURL);
					cout << "### dispatchWithNotification  () is being called." << endl << flush;
					l_unoDispatcher->dispatchWithNotification (*l_urlInURL, l_unoDispatchArgumentPropertiesSequence, Reference <XDispatchResultListener> (l_unoDispatchCommandEventsListener));
					cout << "### dispatchWithNotification  () has returned." << endl << flush;
					l_unoDispatcher->removeStatusListener (Reference <XStatusListener> (l_unoDispatchCommandEventsListener), *l_urlInURL);
					l_unoDispatchCommandEventsListener->additionalMethod ();
					l_unoDispatchCommandEventsListener->dispose ();

Hypothesizer 7
Please suppose that the code after the blank line (the 3rd line) is called repeatedly; then, your code creates new '::com::sun::star::uno::Reference' instances repeatedly, while my code creates only one '::com::sun::star::uno::Reference' instance for each template type.

Objector 45B
But 'source code'-wise, your code wouldn't lighten my labor at all.

Hypothesizer 7
When I see an inefficient code, I deem it to be cumbersome; so, less inefficient code is less cumbersome, for me.

Objector 45B
But 'source code'-wise, your code wouldn't lighten my labor at all!

Hypothesizer 7
That is inevitable, as far as I know.

Objector 45B
. . . Your example is about local UNO objects; how can the smart pointer be used for remote UNO objects?

Hypothesizer 7
The same, but be aware that 'getPointerInReference' method has to take 'true' if querying is necessary.

Objector 45B
What do you mean by "querying is necessary"?

Hypothesizer 7
This is an example code where 'l_unoDispatcherInXNotifyingDispatch' is a '::com::sun::star::uno::Reference <::com::sun::star::frame::XNotifyingDispatch>' instance.

Stage Direction
Hypothesizer 7 writes a piece of example code on the screen.

@C++ Source Code
					UnoObjectPointer <XNotifyingDispatch> l_unoDispatcher (l_unoDispatcherInXNotifyingDispatch);
					if (l_unoDispatcher.getPointerInReference <XUnoTunnel> (true).is ()) {
						cout << "### A 'Reference <XUnoTunnel>' instance has been gotten." << endl << flush;
					}
					if (l_unoDispatcher.getPointerInReference <XWeak> (true).is ()) {
						cout << "### A 'Reference <XWeak>' instance has been gotten." << endl << flush;
					}
					if (l_unoDispatcher.getPointerInReference <XDispatch> ().is ()) {
						cout << "### A 'Reference <XDispatch>' instance has been gotten." << endl << flush;
					}

Hypothesizer 7
The first 2 calls have to take 'true' because the template types are not any sub interface of '::com::sun::star::frame::XNotifyingDispatch', necessitating querying new UNO proxies, while the 3rd call does not have to take 'true' because the template type is a sub interface of '::com::sun::star::frame::XNotifyingDispatch'.

Objector 45B
Oh, I see, but can't I always query?

Hypothesizer 7
You could, but I would not unnecessarily query, because querying is costly.

Objector 45B
Is there any evidence that querying is costly, or your smart pointer is effective, for the matter?

Hypothesizer 7
Let us compare these 3 pieces of code: the 1st -> creating a '::com::sun::star::uno::Reference' instance each time without querying, the 2nd -> creating a '::com::sun::star::uno::Reference' instance each time with querying, the 3rd -> using the smart pointer.

Stage Direction
Hypothesizer 7 writes 3 pieces of performance test code on the screen.

@C++ Source Code
					// creating a '::com::sun::star::uno::Reference' instance each time without querying Start
					Reference <UnoGeneralEventsListener> l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					int l_numberOfIterations = 10000;
					PerformanceMeasurer::setStartTime ();
					for (int l_iterationIndex = 0; l_iterationIndex < l_numberOfIterations; l_iterationIndex ++) {
						Reference <::com::sun::star::lang::XEventListener> l_unoGeneralEventsListenerInXEventListener (l_unoGeneralEventsListener);
					}
					cout << StringHandler::format ("### The elapsed time is %s ns.", StringHandler::getThousandsSeparatedLongString (PerformanceMeasurer::getElapseTimeInNanoSeconds ())) <<  endl << flush;
					// creating a '::com::sun::star::uno::Reference' instance each time without querying End
					
					// creating a '::com::sun::star::uno::Reference' instance each time with querying Start
					Reference <UnoGeneralEventsListener> l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					int l_numberOfIterations = 10000;
					PerformanceMeasurer::setStartTime ();
					for (int l_iterationIndex = 0; l_iterationIndex < l_numberOfIterations; l_iterationIndex ++) {
						Reference <::com::sun::star::lang::XEventListener> l_unoGeneralEventsListenerInXEventListener (l_unoGeneralEventsListener, UNO_QUERY);
					}
					cout << StringHandler::format ("### The elapsed time is %s ns.", StringHandler::getThousandsSeparatedLongString (PerformanceMeasurer::getElapseTimeInNanoSeconds ())) <<  endl << flush;
					// creating a '::com::sun::star::uno::Reference' instance each time with querying End
					
					// using the smart pointer Start
					UnoObjectPointer <UnoGeneralEventsListener> l_unoGeneralEventsListener (new UnoGeneralEventsListener ());
					int l_numberOfIterations = 10000;
					PerformanceMeasurer::setStartTime ();
					for (int l_iterationIndex = 0; l_iterationIndex < l_numberOfIterations; l_iterationIndex ++) {
						Reference <::com::sun::star::lang::XEventListener> & l_unoGeneralEventsListenerInXEventListener (l_unoGeneralEventsListener.getPointerInReference <::com::sun::star::lang::XEventListener> ());
					}
					cout << StringHandler::format ("### The elapsed time is %s ns.", StringHandler::getThousandsSeparatedLongString (PerformanceMeasurer::getElapseTimeInNanoSeconds ())) <<  endl << flush;
					// using the smart pointer End

Objector 45B
. . . Ah-ha.

Stage Direction
Hypothesizer 7 executes the 3 pieces of performance test code, each 3 times. The results are:
The 1st piece
318,124,840
310,278,040
548,278,110

The 2nd piece
801,199,883
576,837,910
587,879,945

The 3rd piece
9,736,969
8,351,116
8,204,377

in nano seconds.


Objector 45B
. . . Well, the difference between the 1st and the 2nd isn't definitive, but I see that the 3rd is incommensurably faster.


5: The Conclusion and Beyond


Hypothesizer 7
Now, we know how to use or not use '::com::sun::star::uno::Reference' safely, efficiently, and handily in handling local or remote UNO objects.

It is imperative to know the fact that usage counts are usually decremented delayedly and the fact that the '::com::sun::star::uno::Reference' template is not so-called "covariant" or so-called "contravariant".

Preparing multiple '::com::sun::star::uno::Reference' instances for one UNO object is tedious, but a smart pointer that concentrates those '::com::sun::star::uno::Reference' instances may help.

The idea of the smart pointer introduced in this article will be applicable also to the other programming languages, in the meaning that UNO proxies of one remote UNO object can be concentrated in the smart pointer (any smart pointer for any local UNO object will be useless because there is no 'Reference' in the other programming languages), as will be seen in some future articles.


References


<The previous article in this series | The table of contents of this series | The next article in this series>