변수 인도 규칙

구조체·/오브젝트 레퍼런스

CORBA 의 구조체는 C++ 에 대하고, 구조체 "struct" 에 매핑 된다.

 // -*- IDL -*-
 struct Profile {
   short short_value;
   long  long_value;
 };

 // -*- C++ -*-
 struct Profile {
   CORBA::Short short_value;
   CORBA::Long  long_value;
 };

 class Profile_var {
   
 };

  • 고정장의 구조체
  • 가변장의 구조체

구조체에 가변장의 멤버 (string, wstring, sequence, (가변장 멤버를 가지는 struct, 가변장 멤버를 가지는 union)가 포함되어 있으면, 구조체는 가변장 데이터로 간주해집니다. 이 경우, 고정장의 구조체와는 다른 C++ 코드가 생성되어 반환값이나 out 파라미터에 있어서의 취급이 다릅니다.

    • _var형 IDL 컴파일러는 IDL 에 있어서의 구조체로부터, C++ 의 구조체와 _var 형의 클래스를 자동적으로 생성합니다. _var 형 클래스는 스마트 포인터와 같이 행동해,

가변장의 구조체로서 _var 클래스를 사용하는 경우, 가변장의 멤버가 할당할 수 있는 메모리는 자동적으로 관리됩니다.

    • _var 형의 변수(예를 들면 var1)로부터 다른_var형의 변수(var2)에 대입을 했을 경우에는, 그 포인터의 소유권이 var2 로 옮겨져, 그 후 var1 는 초기화 혹은 대입을 할 때까지, 사용할 수 없습니다.
    • 구조체가 스코프의 밖에 나오면, 가변장의 멤버가 관련지을 수 있고 있던 모든 메모리는 자동적으로 해방됩니다. 다만, 벌써 소유권을 그 밖에 양도하고 있는_var형 변수가 스코프로부터 나오는 경우, 원의 데이터에 대해서는 개방은 행해지지 않습니다.(소유권을 이미 양도하고 있으므로.)
    • 초기화 혹은 대입된 구조체에 대해서, 다시 초기화 또는 대입을 했을 경우, 원의 데이터에 관련지을 수 있고 있던 메모리는 자동적으로 해방됩니다.
    • 가변장의 멤버에게 오브젝트 레퍼런스가 대입되는 경우는, 반드시 그 오브젝트 레퍼런스의 카피가 작성됩니다.가변장의 멤버에게 포인터가 대입되는 경우, 카피는 작성되지 않습니다.

_var 형

변환 constructor    (T_ptr)

  • 실장예
      _CORBA_ObjRef_Var(T_ptr p) : pd_objref(p) {}

_ptr형의 오브젝트 참조의 소유권은_var형으로 옮기기 위해, 참조 카운트의 증감은 없다.

 MyObject_ptr ptr = obj->get_myobject();
 // ptr 는 적절한 타이밍에 release 되지 않으면 안 된다
 MyObject_var var(ptr);
 // 소유권은 var로 옮겼기 때문에, ptr를 릴리스 할 필요는 없다
 // var가 스코프를 빠지는 등 해체될 때 참조 카운트는 감소 된다
 

변환 constructor    (const T_var&)

  • 실장예
     Object_var(const T_var& p) : pd_ref(T::_duplicate(p.pd_ref)) {}

대입원의_var형의 오브젝트 참조의 소유권은 카피된다.

 MyObject_var var0 = obj->get_myobject();
 // var0는 소유권을 가진다
 MyObject_var var1(var0);
 // 레퍼런스 카운트는 인크리먼트(increment) 되어 var1도 소유권을 가진다

변환 constructor    (const T_member)

  • 실장예

in인수와 in() 함수

단순하게 오브젝트 참조의_ptr형 포인터를 돌려준다. 소유권의 이동은 일어나지 않는다.

  • 실장예
     T_ptr  in() const { return pd_objref; }

통상, 함수의in인수에 오브젝트 참조를 건네줄 때에 사용한다. 오브젝트 참조가 주어진 측의 함수는, 소유권을 가지지 않기 때문에 함수내에서release해선 안 된다. 함수로부터 돌아온 뒤, _var형 변수에 여전히 소유권이 보관 유지되고 있어_var형 변수의 해체시에 오브젝트는release된다.

오브젝트 참조를in인수로서 받는 함수를 정의하는 경우는, _ptr형의 인수로서 정의한다.게다가 함수내에서는, 그 오브젝트의 오퍼레이션을 부르는 것만으로,release등은 가선 안 된다. 또, 함수내에서 오브젝트 참조를 어딘가(글로벌 변수, static 변수, 오브젝트의 멤버등 )에 보존하고 싶은 경우는, 소유권을 카피하기 위해(때문에) duplicate 함수로 복제할 필요가 있다.

  • 사용예
     void myfunc(MyObject_ptr obj)
     {
       obj->function();
       CORBA::release(obj); // ×이것은 해선 안 된다
       m_obj = obj; // ×소유권을 가지고 있지 않다
       m_obj = MyObject::duplicate(obj); // ○소유권을 복제
     }
     
     {// 다른 문맥 
       MyObject_var obj(hoge->get_object());
       myfunc(obj.in()); // 소유권의 이행은 일어나지 않는다
     }
     // 스코프를 빠졌으므로 참조 카운트가 감소 된다

out 인수와 out() 함수

현재 소유하고 있는 참조를release(참조 카운트를 감소) 하고, 레퍼런스의 포인터를 nil에 세트 해 돌려준다. 즉,out()함수 호출 이전에도 해 오브젝트 참조를 보관 유지하고 있는 경우는 그 소유권을 방폐해 참조는 파기된다.

  • 실장예
     T_ptr& out() {
        T_Helper::release(pd_objref);
        pd_objref = T_Helper::_nil();
        return pd_objref;
     }

통상, 함수의out인수에 오브젝트 참조를 건네줄 때에 사용한다.즉, 함수로부터 돌아온 뒤, 이 변수에 새롭게 오브젝트 참조가 보관 유지되고 있는 것이 기대된다. 이 때, 오브젝트 참조의 소유권은 이 변수에 보관 유지되고 있다고 생각한다. out()로 변수를 건네받은 함수측에서는, 어떠한 형태로 오브젝트 참조를 생성 또는 복제하고, 인수에 소유권을 건네줄 필요가 있다.

오브젝트 참조를out인수로서 받는 함수를 정의하는 경우는, _ptr형 참조의 인수로서 정의한다.함수내에서는, 인수는 반드시 nil 오브젝트 참조이며, 한편 통상 어떠한 오브젝트를 소유권을 주어 대입하는 것이 기대된다.

  • 사용예
     void myfunc(MyObject_ptr& obj)
     {
       assert(CORBA::is_nil(obj)); // 반드시 nil 오브젝트
       obj->function(); // nil이므로 오퍼레이션은 부를 수 없다
     
       // m_obj 는_var형의 멤버 변수
       obj = m_obj; // ×소유권을 복제하고 있지 않다.
       // return 후, 함수의 밖에서 마음대로 release 될지도 모른다.
     
       obj = MyObject::duplicate(obj); // ○소유권을 복제하고 있다.
       // return 후, 함수의 밖에서 release 되어도, 오브젝트 참조는 해체되지 않는다.
       return;
     }
     
     {// 다른 문맥
       MyObject_var obj;
       obj = get_object(); // △out 변수로서 사용하므로 건네주기 전에는 아무것도 들어갈 수 없는 것이 좋다
       myfunc(obj.out());
       // 오브젝트가 대입되어 되돌아 왔을 것
       assert(!CORBA::is_nil(obj));
       obj->function();
     }
     // 스코프를 빠졌으므로 참조 카운트가 감소 된다.
     

    inout()

레퍼런스에의 포인터의 참조를 돌려준다.

  • 실장
     T_ptr& inout()    { return pd_objref; }

통상, 함수의inout인수에 오브젝트 참조를 건네줄 때에 사용한다. 즉, 함수내에서는 어떠한 오브젝트 참조가 인수에 들어가 있는 것이 기대되어 오브젝트의 소유권은 함수 측에 옮긴다.또, 함수는 어떠한 오브젝트 참조를 이 인수에게 주어 돌려주는 것이 기대되어 인수 즉 호출해 원의 변수에 소유권을 준다. 함수내에서는 인수에 오브젝트 참조를 새롭게 세트 하는 경우는, 우선release하고 나서 새로운 오브젝트 참조를 생성 또는 복제해 인수에 소유권을 건네줄 필요가 있다.

오브젝트 참조를inout인수로서 취하는 함수는, 설계의 관점으로부터 별로 추천 되지 않는다.만약,inout인수로서 취하는 함수를 정의할 필요가 있는 경우는, _ptr형 참조의 인수로서 정의한다.

  • 사용예
     void myfunc(MyObject_ptr& obj)
     {
       if (!CORBA::is_nil(obj))
       {
         obj->function(); // obj 가 nil가 아니면 오퍼레이션을 부를 수 있다.
       }
     
       CORBA::release(obj); // release 할 책임은 이 함수에 있다
       /*
        * 이 함수내에서, obj에 새로운 오브젝트 참조가 있는 경우에 한정해,
        * 인수를 받은 직후에, _var 변수에 대입해 두는 것으로,
        * 함수 종료시에 자동적으로 참조 카운트를 감소
        * 하는 테크닉을 사용해도 괜찮다.
        * MyObject_var deleter = obj;
        */
     
       // MyObject_var m_obj 로 한다
       obj = m_obj; // × 소유권을 복제하고 있지 않다
       // return 후, 함수의 밖에서 release 될지도 모른다.
       obj = MyObject::_duplicate(m_obj); // ○ obj 에도 MyObject의 소유권이 주어졌다
       // return 후, 함수의 밖에서 release 되어도, 오브젝트 참조는 해체되지 않는다.
     }
     
     {// 다른 문맥
       MyObject_var obj;
       obj = get_object(); // obj 는 소유권을 가지고 있다
       myfunc(obj); // 함수내에서 releae 된다
       // obj 가 가리키는 것은 바뀌고 있을지도 모르다.
     }
     // 스코프를 빠졌으므로 참조 카운트가 감소 된다.

_retn()

현재 가지고 있는 오브젝트 참조의 소유권을 방폐하고 포인터를 돌려준다.

 T_ptr _retn() {
    T_ptr tmp = pd_objref;
    pd_objref = T_Helper::_nil();
    return tmp;
 }

통상, 함수의 반환값에 오브젝트 참조를 돌려주는 경우에 사용된다. 소유권은 함수의 호출 측에 건너므로, 호출측에서는 오브젝트 참조를 파기할 책임이 있다.따라서, 호출측에서 release 하는지, _var형 변수로 받을 필요가 있다.

반대로, 반환값으로 오브젝트 참조를 돌려주는 경우, 호출측에서는 반드시 release에 의해 참조 카운트가 감소 되기 위해, 함수내에서는 _duplicate()등에서 소유권을 복제해 둘 필요가 있다.

  • 사용예
     MyObject_ptr myfunc()
     {
       MyObject_var ret;
       ret = m_obj; // ×소유권이 ret로 옮겨져 버린다.
       // return 후, 함수의 밖에서 release 될지도 모른다.
     
       ret = MyObject::_duplicate(m_obj); // ○소유권의 복제
       // return 후, release가 불려도, m_obj 는 소유권을 계속 보관 유지한다.
     
       return ret._retn();
     }
     
     { // 다른 문맥
       MyObject_var obj;
       obj = myfunc(); // 오브젝트의 소유권을 취득
       obj->function();
     
       MyObject_ptr ptr;
       ptr = myfunc(); //오브젝트의 소유권을 취득
       ptr->function();
     
       CORBA::release(ptr); // 참조 카운트를 감소
      }
      // 스코프를 빠졌으므로 참조 카운트가 감소 된다

규칙의 정리

함수 형 release 책임 함수내
in T_ptr 호출측 오퍼레이션 호출
out T_ptr& 호출측 _duplicate 대입
inout T_ptr& in:함수, out:호출측 release 후, _duplicate 대입
_retn T_ptr 호출측 _duplicate 해 return

_var형, _ptr형의 대입으로의 레퍼런스 카운트

_ptr형에의_var형의 대입

포인터에의 대입.

복제 이루어, 해방하지 않고.

  • 사용예

 { 
  MyObject_var var;
  var = myfunc(); // 오브젝트의 소유권을 취득
 
  MyObject_ptr ptr
  ptr = MyObject::_duplicate(var); //오브젝트의 소유권을 취득(참조 카운트의 인크리먼트(increment))
 
  // ptr = var;
  // 이것은 참조 카운트 에러를 일으킬 우려가 있다.호출 후, ptr와 var는 같은 오브젝트
  // (을)를 찌를 것이다가, 참조 카운트의 보수는 이루어지는거야.var는, 그 대상 오브젝트의 소지를 유지
  // 한다.또, ptr가 그것이 이전에 가리키고 있던 오브젝트나 프록시에의 유일한 포인터였다
  // 그렇다면, 메모리 리크가 생긴다.
 
  CORBA::release(ptr); // 참조 카운트를 감소
 }
 // var에 관해서는, 스코프를 빠졌으므로 참조 카운트가 감소 된다

_var형에의_ptr형의 대입

_var가 보유하고 있는 오브젝트에 대해서 release() 되지만, 인수로 건네받은_ptr형의 오브젝트에 대해서는 duplicate() 되지 않는다.

복제 이루어, 해방 있어.

  • 실장(omniORB)

  inline T_var& operator= (T_ptr p) {
    T_Helper::release(pd_objref);
    pd_objref = p;
    return *this;
  }

  • 사용예

 { 
  MyObject_ptr ptr;
  ptr = myfunc(); // 오브젝트의 소유권을 취득
 
  MyObject_var obj;
  obj = MyObject::_duplicate(ptr); //오브젝트의 소유권을 취득(참조 카운트의 인크리먼트(increment))
 
  CORBA::release(ptr); // 참조 카운트를 감소
 }
 // obj에 관해서는, 스코프를 빠졌으므로 참조 카운트가 감소 된다

_var형에의_var형의 대입

_var가 보유하고 있는 오브젝트에 대해서 release()가 콜 되어 한편, 인수로 건네받은 오브젝트에 대해서도 duplicate()가 콜 된다.

복제 있어, 해방 있어.

  • 실장(omniORB)

  inline T_var& operator= (const T_var& p) {
    if( &p != this ) {
      T_Helper::duplicate(p.pd_objref);
      T_Helper::release(pd_objref);
      pd_objref = p.pd_objref;
    }
    return *this;
  }

  • 사용예

 { 
  MyObject_var var1;
  var1 = myfunc(); // 오브젝트의 소유권을 취득
 
  MyObject_var var2;
  var2 = var1; //오브젝트의 소유권을 취득(참조 카운트는 자동으로 인크리먼트(increment) 된다)
 
  } // var1, var2에 관해서는, 스코프를 빠졌으므로 참조 카운트가 감소 된다

_narrow()로의 레퍼런스 카운트

_narrow() 처리의 과정에 대하고, _narrow()의 호출이 성공했을 경우, 그 대상 오브젝트의 레퍼런스 카운트는 인크리먼트(increment) 되지만, 실패했을 경우는 인크리먼트(increment) 되지 않는다.

감소는 행해지지 않는다.

  • 실장(RTCSK.cc)

 RTC::RTObject_ptr
 RTC::RTObject::_narrow(::CORBA::Object_ptr obj)
 {
   if( !obj || obj->_NP_is_nil() || obj->_NP_is_pseudo() ) return _nil();
   _ptr_type e = (_ptr_type) obj->_PR_getobj()->_realNarrow(_PD_repoId);
   return e ? e : _nil();
 }

  • 실장(omniObjRef.cc)

 void*
 omniObjRef::_realNarrow(const char* repoId)
 {
  // Attempt to narrow the reference using static type info.
  void* target = _ptrToObjRef(repoId);
 
  if( target ) {
    if (!lid ||
    (lid && !lid->deactivated() && lid->servant() &&
     lid->servant()->_ptrToInterface(repoId))) {
 
      omni::duplicateObjRef(this);
    }
    else {
      omniObjRef* objref;
      omniIOR*    ior;
 
      {
    ior = pd_ior->duplicateNoLock();
      }
 
      {
    objref = omni::createObjRef(repoId,ior,1,0);
      }
    }
  }
  else {
    if( _real_is_a(repoId) ) {
      omniObjRef* objref;
      omniIOR* ior;
 
      {
    ior = pd_ior->duplicateNoLock();
      }
 
      {
    objref = omni::createObjRef(repoId,ior,1,_identity());
      }
 
      }
    }
  }
  return target;
 }

규칙

클라이언트측

클라이언트가 호출로부터 오브젝트 참조를 수신한다면, 그 클라이언트는 그 오브젝트 참조가 불필요해졌을 때에는 그것을 개방하지 않으면 안 된다.

(인용: 「CORBA 분산 오브젝트 Orbix를 이용해」 P.98 오브젝트 참조를 위한 메모리 메니지먼트)

서버측

호출 측에 건네주는 참조의 소유권은 방폐된다(즉, 그 참조 카운트는 하나 감소 된다.따라서, 통상은, 참조를 돌려주기 전에 적당한 _duplicate() 함수를 호출하게 된다)

(인용: 「CORBA 분산 오브젝트 Orbix를 이용해」 P.98 오브젝트 참조를 위한 메모리 메니지먼트)

참고 문헌

  • 「CORBA 분산 오브젝트 Orbix를 이용해」저: 숀·베이커 출판사: 피아손·교육

ダウンロード

最新バージョン : 2.1.0-RELESE

統計

Webサイト統計
ユーザ数:3399
プロジェクト統計
RTコンポーネント309
RTミドルウエア35
ツール25
文書・仕様書2

OpenRTM@Github

OpenRTM-aist GitHubサイト

ROS

Robot Operating System

Choreonoid

モーションエディタ/シミュレータ

DAQ-Middleware

ネットワーク分散環境でデータ収集用ソフトウェアを容易に構築するためのソフトウェア・フレームワーク

産総研が提供するRTC集

東京オープンソースロボティクス協会