致命的エラー(セグメンテーションフォールトエラー等の)、思わぬ非効率、面倒なコーディングを避けるために、ローカル/リモートUNOオブジェクトを操作する際に
話題
About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: C++
この記事の目次
- 開始コンテキスト
- ターゲットコンテキスト
- 本体
- 1: ローカルUNOオブジェクトの操作において、いくつかの致命的エラーを起こす
- 2: 使用カウントは通常、遅れてデクリメントされる
- 3: '::com::sun::star::uno::Reference'インスタンスへの自動コンバージョンがいつ起こるか
- 4: 任意のUNOオブジェクトを便利に管理する方法
- 5: 結びとその先
開始コンテキスト
- 読者は、C++の基本的知識を持っている。
- 読者は、UNOとは何か、UNOはLibreOfficeまたはApache OpenOfficeとどう関係しているかの知識を持っている。
- 読者は、UNOの基本的構成要素とそれらにこのシリーズで使われる用語体系の知識を持っている。
ターゲットコンテキスト
- 読者は、ローカルまたはリモートUNOオブジェクトを操作するために、'::com::sun::star::uno::Reference'を安全、効率的、便利に使用するまたはしない方法を知る。
本体
ト書きHypothesizer 7、Objector 45A、Objector 45Bがコンピューターの前にいる。
1: ローカルUNOオブジェクトの操作において、いくつかの致命的エラーを起こす
ト書き
Objector 45Aは叫ぶ、コンピュータスクリーンを見つめながら。
Objector 45A
一体全体、こりゃあ何だ?!
Hypothesizer 7
サー、それは、コンピュータスクリーンです。
Objector 45A
. . .それのことじゃない。これだ!
ト書き
Objector 45Aは、そのコンピュータスクリーン上の一点を指す。
Hypothesizer 7
それはコンピュータスクリーン上のある点です。ピクセル座標における(242、1012)を中心とする半径10の円内の点だと推察いたします。
Objector 45A
本当に?お前の視覚にはそれだけの精度があるのか?とにかく、このメッセージは何だ?
Hypothesizer 7
「double free or corruption (out)」と書いてあるとお教えしろということでしょうか?
Objector 45A
それは読めるんだよ。. . .何でエラーなのかを聞いているんだ。俺のコードの何がいけない?
Hypothesizer 7
あの、あなたのコードの何がいけないかを私は知ることはできません、あなたのコードを見ることなしには。
ト書き
Objector 45Aは、自分のコードをスクリーン上に示す。Hypothesizer 7は、コードを眺める。
@C++ ソースコード
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
. . .'l_unoDispatchCommandEventsListener'および'l_unoGeneralEventsListener'というローカルUNOオブジェクト群を、スタック内に作成されていますね。
Objector 45A
悪いか?
Hypothesizer 7
必ずしも悪くありません。それらのUNOコンポーネント群の定義を見せていただけますか?
Objector 45A
お前の指示にしたがったものだ。
ト書き
Objector 45Aは、'UnoDispatchCommandEventsListener'および'UnoGeneralEventsListener'の定義をスクリーン上に示す。Hypothesizer 7は、それらの定義を眺める。
@C++ ソースコード
#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
理解いたしました。
Objector 45A
何を理解したんだ?
Hypothesizer 7
それらのUNOコンポーネントをそのように定義すべきではありません、もしも、それらをあなたのやり方で使われるのであれば。
Objector 45A
お前の指示にしたがって定義したんだぞ. . .
Hypothesizer 7
それらは、スタック内にインスタンス化されるように意図されていません。
Objector 45A
ローカルUNOオブジェクトをスタック内に作成するのは、「必ずしも」悪くないと言っただろうが. . .
Hypothesizer 7
そのとおりです。
Objector 45A
「そのとおり」?ただ「そのとおり」?
Hypothesizer 7
えーと、その記事を注意深くお読みになりましたか?
Objector 45A
もちろん、してない!誰がそうする?
Hypothesizer 7
. . .C++ UNOガーベッジコレクションメカニズムがそこで説明されておりますが、それは、それがストーリーの前提だからです。
Objector 45A
前提などくそくらえ!それじゃあ、そのローカルUNOオブジェクトをヒープ内に次のように作成するが、それでも、セグメンテーションフォールトエラーが起こるぞ!
ト書き
Objector 45Aは、自らのコードをスクリーン上に示す。Hypothesizer 7は、そのコードを見渡す。
@C++ ソースコード
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
. . .C++ UNOガーベッジコレクションメカニズムを本当に理解されていませんよね?
ト書き
Objector 45Aは、悪態をつき、C++ UNOガーベッジコレクションメカニズムの記述を読む、とてもしぶしぶと。
Objector 45A
. . .オーケー、俺のコードがうまくいかない理由が分かったぞ: スタック内のローカルUNOオブジェクトたちに関しては、C++ UNOガーベッジコレクションメカニズムがローカルUNOオブジェクトたちを削除しようとするが、スタック内のオブジェクトたちを削除できないんだろう?
Hypothesizer 7
えーと、それが、勿論、ストーリーの一部です. . .
Objector 45A
それじゃあ、これでうまくいくはずだ!
ト書き
Objector 45Aは、当該UNOコンポーネント群の、ガーベッジコレクトされないバージョンを作成する。
@C++ ソースコード
#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
. . .意図なさっていることはわかりますが、しかし、. . .
Objector 45A
UNOオブジェクトの自動廃棄を無くしたぞ、'release ()'メソッドをオーバーライドすることによってな、何て独創的なアイデアだろう!
Hypothesizer 7
えーと. . .
ト書き
Objector 45Aは、自らのスタックベースのプログラムの変更されたバージョンを実行するが、セグメンテーションフォールトエラーを起こす。
Objector 45A
はあ?ありえない!
Hypothesizer 7
実のところ、大いにありえます、あなたのプログラムは、時折、成功するかもしれませんが、運がよければ。
あなたのヒープベースのプログラムも同様だろうとご忠告しておきます。
2: 使用カウントは通常、遅れてデクリメントされる
Hypothesizer 7
使用カウントは通常、遅れてデクリメントされることをご理解される必要があります。
Objector 45A
はあ?「遅れて」とはどういく意味だ?
Hypothesizer 7
例えば、あなたのコード内で、'l_unoDispatchCommandEventsListener'の使用カウントは、通常、'dispatchWithNotification'メソッドがリターンした後、前番号へ即座には戻りません。
Objector 45A
. . .それじゃあ、いつ、前番号へ戻るんだ?
Hypothesizer 7
そのうちに。
Objector 45A
「そのうちに」はばくぜんとした言葉だぞ。. . .しかし、とにかく、だから何だ?俺のUNOコンポーネント群は使用カウントを全然使わないんだから、使用カウントんがいつデクリメントされようが、どうでもいいだろう?
Hypothesizer 7
それがよくないので、実のところ。あなたのUNOコンポーネントの振る舞いがどうであろうが、当該UNOサーバー(LibreOfficeまたはApache OpenOfficeのインスタンス)は、あくまでも使用カウントをデクリメントしようとし、もしも、あなたのUNOオブジェクトが既に廃棄されていれば、セグメンテーションフォールトエラーを起こすでしょう。
Objector 45A
ああ、確かに。. . .それじゃあ、俺のプログラムはスリープすればいいわけか、使用カウントが'0'へデクリメントされるまで. . .そのうちに?
Hypothesizer 7
そうもできますが、UNOコンポーネントに使用カウントを定期的にポーリングさせたりしたくないでしょう?
Objector 45A
えーと、特にしたいわけじゃないが、もしも必要であれば. . .
Hypothesizer 7
もしも、どうしても、C++ UNOガーベッジコレクションメカニズムを出し抜かれたいのであれば、以下の方がよりよい解決策かもしれません、私は特にお勧めしませんが。
ト書き
Hypothesizer 7は、当該UNOコンポーネント群の、自らの、ガーベッジコレクトされないバージョンを作成する。
@C++ ソースコード
#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
. . .じゃあ、UNOオブジェクトは、自らに通知するわけだ、使用カウントが'0'へデクリメントされた時に。
Hypothesizer 7
そのUNOコンポーネントをご使用になれば、デストラクタが呼ばれた後に使用カウントがデクリメントされがちであることを、アウトプットが示すでしょう。
Objector 45A
えーと、「そのうちに」とお前は言ってるが、廃棄が無期限に保留にされることはないのか?
Hypothesizer 7
いいポイントです。厳密に言うと、UNOオブジェクトが無期限に留め置かれることがないという保証はありませんが、実際的に言うと、ローカルUNOオブジェクトが特に理由もなく長い時間留め置かれるとは思いません。
Objector 45A
なぜ、「特にお勧めしません」のか?
Hypothesizer 7
私であれば、むしろ、C++ UNOガーベッジコレクションメカニズムに沿うでしょう、出し抜くよりは。
Objector 45A
しかし、俺は、いつ自分のUNOオブジェクトたちが死ぬか、コントロールしたいのだ!
Hypothesizer 7
その気持ちはとてもよく理解できます、本当に、しかし、先ほど述べた非保証性が躊躇させます。
3: '::com::sun::star::uno::Reference'インスタンスへの自動コンバージョンがいつ起こるか
Objector 45A
それじゃあ、UNOコンポーネントの元の定義でいくものと仮定して、こうすべきということか?
ト書き
Objector 45Aは、自らのプログラムをスクリーン上で変更する。
@C++ ソースコード
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
. . .ふーむ. . .
Objector 45A
何だ?
Hypothesizer 7
それらの自動コンバージョンにはお気づきですか?
Objector 45A
「それらの」?どれらだ?
Hypothesizer 7
'l_unoDispatchCommandEventsListener->addEventListener'コールにおける、'l_unoGeneralEventsListener'の'::com::sun::star::uno::Reference <::com::sun::star::lang::XEventListener>'インスタンスへのコンバージョン、'l_unoDispatcher->addStatusListener'コールにおける、'l_unoDispatchCommandEventsListener'の'::com::sun::star::uno::Reference <::com::sun::star::frame::XStatusListener>'インスタンスへの へのコンバージョン、'l_unoDispatcher->dispatchWithNotification'コールにおける、'l_unoDispatchCommandEventsListener'の'::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>'インスタンスへのコンバージョン、'l_unoDispatcher->removeStatusListener'コールにおける、'l_unoDispatchCommandEventsListener'の'::com::sun::star::uno::Reference <::com::sun::star::frame::XStatusListener>'インスタンスへのコンバージョンです。ご存じのとおり、それらの引数はそれぞれ、本当には、'::com::sun::star::uno::Reference'タイプのものです。
Objector 45A
. . .だから何だ?
Hypothesizer 7
それらは非効率です: コール毎に、一時的な'::com::sun::star::uno::Reference'インスタンスが作成されます。
Objector 45A
そんなの本当に問題か?「コール毎」と言われても、たった4コールだぞ. . .
Hypothesizer 7
もしも、そのファンクションが1,000回コールされたら、4,000コールになります。
Objector 45A
そのとおりだ、しかし、それでも、実際的に問題になるとは思わんな。
Hypothesizer 7
あなたのプログラム次第では、そうかもしれません。. . .それにしても、私は、明白に非効率なコードをあえて書こうとはしないでしょう。
Objector 45A
おう?それじゃあ、お前のコードはどのようになるんだ?
Hypothesizer 7
以下は洗練されていませんが、より良いでしょう。
ト書き
Hypothesizer 7は、自らのバージョンをスクリーン上に書く。
@C++ ソースコード
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
おえ!醜いなあ!
Hypothesizer 7
えーと、あなたの「醜い」感を私は共有しません。. . .あなたのバージョンはただ、醜いコンバージョンを隠しているだけです。確かに、隠れていますが、それらはそこにあります、いずれにせよ、そして、私は醜さをより感じます、それが隠されているという理由で。
Objector 45A
俺のバージョンの方がずっと短い!
Hypothesizer 7
ソースコードの短さは、コードの効率とも可読性とも正に相関しませんが、効率や可読性がより重要なのです、私の意見では。
Objector 45A
俺のバージョンの方が明らかにかっこいい!
Hypothesizer 7
私はそのような「かっこ」よさを尊重しません。そのような格好よさは、ただの化粧であって、その表面を透かして見ることのできない人々のみを欺くことができます。
Objector 45A
. . .お前のバージョンはだめだ、なぜなら、以下は、自動コンバージョンを取り除いたが、よりかっこいい、'acquire'と'release'がなくなったからな!
ト書き
Objector 45A modifies his program on the screen. Objector 45Aは、自らのプログラムをスクリーン上で変更する。
@C++ ソースコード
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
. . .あの、それは、自動コンバージョンを取り除きませんが。
Objector 45A
はあ?なぜだ?
Hypothesizer 7
ご存じのとおり、クラステンプレートは、いわゆる「共変」でもいわゆる「反変」でもありません。
Objector 45A
だから?
Hypothesizer 7
'::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>'は、'::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>'等とis-a関係になく、したがって、'::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>'インスタンスは、'::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>'等のインスタンスとは見なされません。
Objector 45A
なぜだ?
Hypothesizer 7
'::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>'は、そのインスタンスは任意の'UnoDispatchCommandEventsListener' UNOオブジェクトまたはUNOプロキシのアドレスを格納できるが、'UnoDispatchCommandEventsListener' UNOオブジェクトまたはUNOプロキシアドレスだけを格納できることを意味し、それは、'::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>'の定義を満たしません。
Objector 45A
そうかい?
Hypothesizer 7
'UnoDispatchCommandEventsListener' UNOオブジェクトまたはUNOプロキシアドレスのみを格納できるものというのは、'::com::sun::star::frame::XDispatchResultListener' UNOオブジェクトまたはUNOプロキシアドレスを格納できるものではなく、それは、'::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener>'の定義の必須命令です。. . .論理は、Java配列に関して記述されたものと同じです。
Objector 45A
. . .厳密に言えば、そうかもしれないが. . .
Hypothesizer 7
それは常に厳密に言われなければなりません、サー。. . .もしも、ある'::com::sun::star::uno::Reference <UnoDispatchCommandEventsListener>'インスタンスが'::com::sun::star::uno::Reference <::com::sun::star::frame::XDispatchResultListener> &'引数へ渡されることを許されてしまったら、そのファンクションは、ある'::com::sun::star::frame::XDispatchResultListener'(しかし、'UnoDispatchCommandEventsListener'ではない)インスタンスアドレスをそれに入れようと試みる可能性があり、それは、問題になります。
Objector 45A
. . .そういうケースもあるかもしれんがね. . .
Hypothesizer 7
お分かりでしょうが、そういう問題を防ぐのが、静的型付けされたプログラミング言語であることの要点です。
Objector 45A
どうでもいいが. . .
Objector 45B
あなたたちは、ローカルUNOオブジェクトについて話してたけど、リモートUNOオブジェクトについては、自動コンバージョンを使用することなんてできもしないでしょう、もし仮に、私が「醜い」非効率性を受け入れるつもりだとしても?
Hypothesizer 7
マダム、'::com::sun::star::uno::Reference'インスタンスへの自動コンバージョンが起こることができるのは、1) ソースが行き先テンプレートタイプまたはそのサブクラスのアドレスである場合、例えば、ソースが'::com::sun::star::frame::XDesktop2 *'アドレスで行き先が'::com::sun::star::uno::Reference <::com::sun::star::frame::XDesktop> &'である場合、2) ソースが行き先テンプレートタイプのサブクラスをテンプレートタイプとする'::com::sun::star::uno::Reference'インスタンスである場合、例えば、ソースが'::com::sun::star::uno::Reference <::com::sun::star::frame::XDesktop2>'インスタンスで、行き先が'::com::sun::star::uno::Reference <::com::sun::star::frame::XDesktop> &'である場合、です。
Objector 45B
うん?ああ。それじゃあ、一部のケースにおいてのみ、リモートUNOオブジェクトについて自動コンバージョンが起こるかもしれないと。
4: 任意のUNOオブジェクトを便利に管理する方法
Objector 45B
いずれにしろ、1つのUNOオブジェクトに対して、いろんなテンプレートタイプのために、複数の'Reference'インスタンスを作成しないといけないというのは厄介なのよね。
Hypothesizer 7
分かります。
Objector 45B
. . .それが、UNOプログラミングでうんざりするところなのよね?
Hypothesizer 7
分かります。
Objector 45B
. . .あなたそれしか言えないわけ?「分かります」?
Hypothesizer 7
私が言えるのは、あるスマートポインタが役立つかもしれないということです。
Objector 45B
「あるスマートポインタ」ってどういう意味?
Hypothesizer 7
私が意味するのは以下です。
ト書き
Hypothesizer 7は、自らのスマートポインタコードをスクリーン上に示す。
UnoObjectPointer.hpp
@C++ ソースコード
#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++ ソースコード
#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
. . .えーと、よく分からないけど. . .
Hypothesizer 7
そのスマートポインタは、1つのUNOオブジェクトに対して、複数の'::com::sun::star::uno::Reference'インスタンスを一ヵ所に集中させます。
Objector 45B
それは、どのように使われるわけ?
Hypothesizer 7
以下が使用例です。
ト書き
Hypothesizer 7は、自らの例コードをスクリーン上に示す。
@C++ ソースコード
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
. . .それが以下よりもどう厄介でないのか、分からないんだけど。
ト書き
Objector 45Bは、自らの例コードをスクリーン上で書く。
@C++ ソースコード
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
そこの空行(第3行)の後のコードが繰り返しコールされると想定してください。すると、あなたのコードは、新たな'::com::sun::star::uno::Reference'インスタンスを繰り返し生成します、それに対して、私のコードは、テンプレートタイプ毎に、ただ1つの'::com::sun::star::uno::Reference'インスタンスしか生成しません。
Objector 45B
でも、ソースコード的には、あなたのコードは、私の労働を全然、軽くしてくれない。
Hypothesizer 7
非効率なコードを見ると、私はそれを厄介だと見なします。したがって、より非効率でないコードは、より厄介でないのです、私にとっては。
Objector 45B
でも、ソースコード的には、あなたのコードは、私の労働を全然、軽くしてくれない!
Hypothesizer 7
それは避けることができません、私が知る限り。
Objector 45B
. . .あなたの例は、ローカルUNOオブジェクトについてだけど、そのスマートポインタは、リモートUNOオブジェクトに対してはどう使えるわけ?
Hypothesizer 7
同じことですが、'getPointerInReference'メソッドは'true'を取らないといけないことにご注意ください、クエリーを行なうことが必要であれば。
Objector 45B
「クエリーを行なうことが必要」ってどういう意味?
Hypothesizer 7
以下は、例コードです、そこで、'l_unoDispatcherInXNotifyingDispatch'は、'::com::sun::star::uno::Reference <::com::sun::star::frame::XNotifyingDispatch>'インスタンスです。
ト書き
Hypothesizer 7は、例コードをスクリーン上に書く。
@C++ ソースコード
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
最初の2コールは、'true'を取らなければなりませんが、それは、そこのテンプレートタイプたちが'::com::sun::star::frame::XNotifyingDispatch'のサブインターフェイスでなく、新たなUNOプロキシたちのクエリーを行なうことが必要になるからです。その一方、第3コールは、'true'を取る必要がありませんが、それは、そのテンプレートタイプが'::com::sun::star::frame::XNotifyingDispatch'のサブインターフェイスだからです。
Objector 45B
ああ、分かった、でも、常にクエリーしちゃだめなの?
Hypothesizer 7
だめではありませんが、私であれば、不必要にクエリーはしないでしょう、クエリー実行には負荷がかかりますから。
Objector 45B
クエリー実行に負荷がかかるという証拠はあるの、または、あなたのスマートポインタが効率的だという、さらに言えば?
Hypothesizer 7
以下の3個のコードを比較してみましょう: 1番目 -> 毎回、クエリー実行することなく、'::com::sun::star::uno::Reference'インスタンスを生成する、2番目 -> 毎回、クエリーを実行して、'::com::sun::star::uno::Reference'インスタンスを生成する、3番目 -> 当該スマートポインタを使用する。
ト書き
Hypothesizer 7は、3個のパフォーマンステストコードを、スクリーン上で書く。
@C++ ソースコード
// 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
. . .ははあ。
ト書き
Hypothesizer 7は、上記3個のパフォーマンステストコードを実行する、それぞれ3回づつ。結果は以下のとおり:
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
. . .えーと、1番目と2番目の違いは決定的じゃないけど、3番目は、桁違いに速いことは分かるわ。
5: 結びとその先
Hypothesizer 7
これで、ローカルまたはリモートUNOオブジェクトを操作するために、'::com::sun::star::uno::Reference'を安全、効率的、便利に使用するまたはしない方法を知りました。
使用カウントは通常、遅れてデクリメントされるという事実および'::com::sun::star::uno::Reference'テンプレートはいわゆる「共変」でもいわゆる「反変」でもないという事実を知ることが必要です。
1個のUNOオブジェクトに対して複数の'::com::sun::star::uno::Reference'インスタンスを用意することは面倒ですが、そうした'::com::sun::star::uno::Reference'インスタンス群を集中させる、あるスマートポインタが役立つかもしれません。
本記事で紹介されたスマートポインタのアイデアは、他のプログラミング言語群にも適用できるでしょう、1個のリモートUNOオブジェクトのUNOプロキシ群をそのスマートポインタ内に集中させることができるという意味で(ローカルUNOオブジェクトのためのスマートポインタというのは無用でしょう、'Reference'など、他のプログラミング言語には存在しないので)、いくつかの以降の記事で見るとおり。