Weak reference

In XPCOM, a weak reference is a special object that contains a pointer to an XPCOM object, but does not keep that object alive. If the referent object is destroyed before the weak reference, the pointer inside the weak reference is set to nsnull.

ใชใœใ“ใ‚Œใ‚’ไฝฟใ†ๅฟ…่ฆใŒใ‚ใ‚‹ใฎใงใ—ใ‚‡ใ†ใ‹๏ผŸ

When you hold an owning reference on an object (i.e., you have AddRefed it), you are holding that object in existence for the duration of your reference. This isn't always appropriate, and can lead to trouble. If, for instance, this owning reference is part of a cycle of owning references (e.g., if the referenced object also holds a owning reference back to you), then none of the objects in the cycle can be reclaimed without taking special measures.

There are less severe situations. A naive design for an observer/observable relationship would require the observable to hold a owning reference to the observer. After all, the observable must send messages to each observer, notifying it of the appropriate state changes. To do that, it will call a method on the observer, so it needs a pointer. And the call would fail if the pointer were allowed to dangle, therefore, the pointer should be a owning reference. This design, however, is flawed, as it holds the observer in existence longer than would otherwise be necessary. The observer may only need a short life compared to the thing being observed. It might go away after the first interesting event, even. But in this design, by hitching its life to the observable, it is kept on life-support long past any need or use.

What is actually needed in this case, is either out-of-band signaling, where when the observer wants to go away, it unregisters itself from the observable, which then releases its owning reference, allowing the observer to die, or else a new kind of reference. This document describes an implementation of weak references. A weak reference does not hold its referent in existence, but also will not dangle. When the referent is destroyed, the weak reference automatically becomes nsnull. This technique can significantly simplify certain relationships, and you should consider it when an owning reference is inappropriate, but where a raw pointer might end up dangling.

ใฉใฎใ‚ˆใ†ใซไฝฟใ†ใฎใงใ—ใ‚‡ใ†ใ‹๏ผŸ

ใ‚ตใƒณใƒ—ใƒซใ‚’ใ“ใ“ใซๆŒ™ใ’ใพใ™ใ€‚ๆ–ฐใ—ใ„ๆ‰€ใจ่ˆˆๅ‘ณใ‚’ๅผ•ใใใ†ใชๆ‰€ใฏใ€ๅผท่ชฟใ—ใฆ่กจ็พใ—ใพใ™ใ€‚

#include "nsWeakPtr.h"

// ...

// ๅผฑใ„ๅ‚็…งใ‚’ๅพ—ใ‚‹ใฎใฏใ€็ฐกๅ˜ใงใ™...
nsWeakPtr weakPtr = getter_AddRefs( NS_GetWeakReference(aFooPtr) );

// ...

{   // ...ใ—ใ‹ใ—ใ€ๅผฑใ„ๅ‚็…งใ‚’ไฝฟใ†ใซใฏใ€(็Ÿญๅ‘ฝใฎ) ๆ‰€ๆœ‰ใ™ใ‚‹ๅ‚็…งใ‚’ๅฟ…่ฆใจใ—ใพใ™ใ€‚
  nsCOMPtr<nsIFoo> tempFooPtr = do_QueryReferent(weakPtr);
  if ( tempFooPtr )
    tempFooPtr->SomeFooMethod(...);
  // ใใ†ใงใชใ„ใจใ€ใ€Œๆœฌๅฝ“ใฎใ€ใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใŒ็„กใใชใฃใฆใ—ใพใ„ใพใ™ใ€‚
}

ใ—ใ‹ใ—ใ€ๅฎŸ้š›ใฎไพ‹ใงใฏใ€ๅผฑใ„ๅ‚็…งใฏใƒกใƒณใƒใƒผๅค‰ๆ•ฐใจใ—ใฆไฟๆŒใ•ใ‚Œใ‚‹ๅ ดๅˆใŒๅคšใ„ใงใ—ใ‚‡ใ†ใ€‚ไปฅไธ‹ใฎไพ‹ใงใฏใ€nsObservable ใฏใ€ใ‚คใƒ™ใƒณใƒˆใ‚’ๅ ฑๅ‘Šใ™ใ‚‹ใŸใ‚ใซใ€ใใ‚Œใžใ‚Œใฎใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใธใฎๅ‚็…งใ‚’ไฟๆŒใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ใ—ใ‹ใ—ใ€nsObservable ใฏใ€ใƒ€ใƒณใ‚ฐใƒชใƒณใ‚ฐใƒใ‚คใƒณใ‚ฟใƒผใ‚’้˜ฒใใŸใ‚ใ ใ‘ใซใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใ‚’ไฟๆŒใ™ใ‚‹ใฎใฏใ€ๆœ›ใพใ—ใใ‚ใ‚Šใพใ›ใ‚“ใ€‚ใใฎใŸใ‚ใ€nsIObserver ใธใฎๆ‰€ๆœ‰ใ™ใ‚‹ๅ‚็…งใ‚’ไฟๆŒใ™ใ‚‹ไปฃใ‚ใ‚Šใซใ€ๅผฑใ„ๅ‚็…งใ‚’ไฟๆŒใ—ใพใ™ใ€‚ๅผฑใ„ๅ‚็…งใฏใ€ไบบ็‚บ็š„ใซใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใฎ็”Ÿๅญ˜ๆœŸ้–“ใ‚’ไผธใฐใ—ใŸใ‚Šใ—ใพใ›ใ‚“ใ€‚ใใฎไธŠใ€ใƒ€ใƒณใ‚ฐใƒชใƒณใ‚ฐใ™ใ‚‹ใ“ใจใ‚‚ใ—ใชใ„ใฎใงใ™ใ€‚

ไปฅไธ‹ใงใฏใ€ๆธกใ•ใ‚Œใฆใใ‚‹ nsIObserver ใŒ nsISupportsWeakReference ใ‚‚ๅฎŸ่ฃ…ใ—ใฆใ„ใ‚‹ใจไปฎๅฎšใ—ใฆใ„ใพใ™ใ€‚ไธ€ใคใฎใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใฎ็ฎก็†ใฎไป•ๆ–นใ‚’ๅ‚่€ƒใซใ™ใ‚Œใฐใ€ใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใฎใƒชใ‚นใƒˆใฎ็ฎก็†ใฎไป•ๆ–นใซใคใ„ใฆๆŽจๆธฌใ™ใ‚‹ใ“ใจใฏใงใใ‚‹ใงใ—ใ‚‡ใ†ใ€‚

class nsObservable
  {
    public:
      // ...
      nsresult AddObserver( nsIObserver* );
      nsresult NotifyObservers( nsIMessage* );
      // ...
    private:
      nsWeakPtr mObserver;
  // ...ใ‚ใ‚‹ใ„ใฏใ“ใ“ใซใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใฎใƒชใ‚นใƒˆใŒใ‚ใ‚‹ใจๆƒณๅƒใ—ใฆใใ ใ•ใ„
  };

// ...

nsresult
nsObservable::AddObserver( nsIObserver* aObserver )
  {
    mObserver = getter_AddRefs( NS_GetWeakReference(aObserver) );
      // ...ใ‚ใ‚‹ใ„ใฏใ“ใ‚Œใ‚’ใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใฎใƒชใ‚นใƒˆใซ่ฟฝๅŠ ใ—ใฆใใ ใ•ใ„
    return NS_OK;
  }

nsresult
nsObservable::NotifyObservers( nsIMessage* aMessage )
  {
    nsCOMPtr<nsIObserver> observer = do_QueryReferent(mObserver);
    if ( observer )
      observer->NoticeMessage(aMessage);
    else
      mObserver = 0;
      // ใ‚ใ‚‹ใ„ใฏใ“ใฎใ‚ชใƒ–ใ‚ถใƒผใƒใƒผใ‚’ใƒชใ‚นใƒˆใ‹ใ‚‰ๅ–ใ‚Š้™คใใ“ใจใงใ€ใใ‚Œใฏใชใใชใฃใฆใ—ใพใ†ใงใ—ใ‚‡ใ†
    return NS_OK;
  }

// ...

nsWeakPtr ใŒ nsCOMPtr ใจใกใ‚‡ใ†ใฉๅŒใ˜ใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใ‚’ๆŒใคใ“ใจใŒใ‚ญใƒผใซใชใ‚Šใพใ™ใ€‚ๅฎŸใฏใ€nsWeakPtr ใฏใ“ใฎใ‚ˆใ†ใซๅฎš็พฉใ•ใ‚Œใฆใ„ใพใ™ใ€‚

typedef nsCOMPtr<nsIWeakReference> nsWeakPtr;

ใ“ใ‚Šใ‚ƒๆœ€ไฝŽใ ๏ผ

ใ“ใฎๅผฑใ„ๅ‚็…งใฎๅฎŸ่ฃ…ใŒใ‚ใชใŸใŒๆœ›ใ‚€ใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใ‚’ๆไพ›ใ—ใชใ„ใ“ใจใซใ€ใŠใใ‚‰ใไปŠใพใงใซๆฐ—ใฅใ„ใŸใงใ—ใ‚‡ใ†ใ€‚

ใชใœใ€ๅผฑใ„ๅ‚็…งใฎไธŠใฎ็งใฎใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใƒกใ‚ฝใƒƒใƒ‰ใ‚’็›ดๆŽฅๅ‘ผในใชใ„ใฎใงใ—ใ‚‡ใ†ใ‹๏ผŸ

ใ‚ใชใŸใฏใ€ใ“ใฎๅผฑใ„ๅ‚็…งใฎไป•็ต„ใฟใ‚’ไฝฟใฃใฆใ€ใ‚ใชใŸใŒๅฎŸ้š›ใซไฝฟใ„ใŸใ„ใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใ‚’ๅฎŸ่ฃ…ใ™ใ‚‹ใƒใ‚คใƒณใ‚ฟใƒผใ‚’ๅพ—ใ‚‰ใ‚Œใ‚‹ใ“ใจใ‚’ๆœ›ใ‚“ใงใ„ใ‚‹ใงใ—ใ‚‡ใ†ใ€‚ไพ‹ใˆใฐใ€

// ๆณจ: ๅฎŸ้š›ใซใฏใ“ใฎใ‚ˆใ†ใชๅฎŸ่ฃ…ใงใฏใ‚ใ‚Šใพใ›ใ‚“
nsWeakPtr<nsIFoo> weakFooPtr = fooPtr;
// ...
if ( weakFooPtr )
  status = weakFooPtr->SomeFooMethod(...);

ใ“ใ‚Œใฏใ€ๅˆ็†็š„ใช่ฆๆฑ‚ใงใ™ใ€‚ใ—ใ‹ใ—ใ€่‡ชๅ‹•็š„ใซๅฎŸ่ฃ…ใ™ใ‚‹ใฎใฏใ€ใจใฆใ‚‚้ซ˜ใใคใใฎใงใ™ใ€‚็ถ™ๆ‰ฟใงใ‚‚ใ€ใƒ†ใƒณใƒ—ใƒฌใƒผใƒˆใงใ‚‚ใ€ใƒžใ‚ฏใƒญใงใ‚‚่‡ชๅ‹•็š„ใซใ™ในใฆใฎใƒกใ‚ฝใƒƒใƒ‰ๅ‘ผใณๅ‡บใ—ใ‚’ๅฎŸ้š›ใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใธ่ปข้€ใ™ใ‚‹ใฎใ‚’ๆ”ฏๆดใ—ใฆใใ‚Œใพใ›ใ‚“ใ€‚XPIDL ใฏใ€(ใ‚‚ใ—ไฟฎๆญฃใ™ใ‚Œใฐ) ใใฎใ‚ˆใ†ใชๅฎŸ่ฃ…ใ‚’ไฝœๆˆใงใใ‚‹ใ‹ใ‚‚ใ—ใ‚Œใพใ›ใ‚“ใ€‚ใใ†ใงใชใ‘ใ‚Œใฐใ€ไธŠใง่ญฐ่ซ–ใ—ใŸใ‚ˆใ†ใชใ“ใจใ‚’ๆ‰‹ใงๆ›ธใใ“ใจใŒใงใใพใ™ใ€‚ๆฅตใ‚ใšใ‹ใงใ™ใŒใ€ใใฎไป–ใฎใ‚ณใ‚นใƒˆใ‚‚ใ‚ใ‚Šใพใ™ใ€‚ใใ‚Œใฏใ€้–“ๆŽฅๅ‘ผใณๅ‡บใ—ใซใ‚ˆใ‚Šใ€ๅ‘ผใณๅ‡บใ—ใ”ใจใซใ‹ใ‹ใ‚‹ไฝ™ๅˆ†ใชใ‚ณใ‚นใƒˆใงใ™ใ€‚ใใ—ใฆๅ˜็ด”ใชๅฎŸ่ฃ…ใงใฏใ€ๅฏพ่ฑกๅฎŸ่ฃ…ใธใฎใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใ”ใจใซไฝ™ๅˆ†ใชใƒใ‚คใƒณใ‚ฟใƒผใ‚’่ฟฝๅŠ ใ—ใพใ™ใ€‚

ใชใœใƒšใ‚ขใฎ้–“ใงๅ˜ใซ QueryInterface ใงใใชใ„ใฎใงใ—ใ‚‡ใ†ใ‹๏ผŸ

ใ‚ใชใŸใŒไฟๆŒใ—ใฆใ„ใ‚‹ nsIWeakReference ใฏใ€ๆœฌๅฝ“ใซๅ˜ใซๅฏพ่ฑกใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆไธŠใฎใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใฎใ‚ˆใ†ใซๆ„Ÿใ˜ใ‚‰ใ‚Œใ‚‹ใงใ—ใ‚‡ใ†ใ€‚ไบŒใคใฎ้–“ใงๅ˜ใซ QueryInterface ใ‚’ๅฎŸ่กŒใ—ใŸใ„ใฎใฏใ€ๅˆ็†็š„ใชใ“ใจใงใ™ใ€‚ใชใœไฝ™ๅˆ†ใชๅ‘ผใณๅ‡บใ— GetWeakReference ใจ QueryReferent ใŒๅฟ…่ฆใชใฎใงใ—ใ‚‡ใ†ใ‹ย ? ๅผฑใ„ๅ‚็…งใŒๅฎŸ้š›ใซๅฏพ่ฑกใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใซ้›†็ด„ใ•ใ‚Œใฆใ„ใ‚Œใฐๅฏ่ƒฝใชใ‚ˆใ†ใซๆ€ใˆใพใ™ใ€‚

ใ“ใ“ใงใฎๅ•้กŒใฏใ€QueryInterface ใงใ™ใ€‚QueryInterface ใฏใ€COM ใŒๅ‹•ไฝœใ™ใ‚‹ใฎใซๅฟ…่ฆใชๅคšใใฎใ“ใจใ‚’ๆบ€ใŸใ™ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ใ“ใ‚Œใ‚‰ใฎ่ฆๆฑ‚ใฎๅ…ƒใงใฏใ€ๅŒใ˜ (้›†็ด„ใ™ใ‚‹) ใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใซๅฏพใ—ใฆๅŒใ˜ใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใฎ QueryInterface ใ‚’ๅ‘ผใณๅ‡บใ—ใŸๅ ดๅˆใฏใ€ๅŒใ˜็ตๆžœใซใชใ‚‰ใชใ‘ใ‚Œใฐใชใ‚Šใพใ›ใ‚“ใ€‚ใ“ใ‚Œใฏใ€ใฉใฎใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใƒใ‚คใƒณใ‚ฟใƒผใ‚’้€šใ˜ใฆๅ‘ผใณๅ‡บใใ†ใจใ‚‚ใ€ใ„ใคๅ‘ผใณๅ‡บใใ†ใจใ‚‚่ฆๆฑ‚ใ•ใ‚Œใ‚‹ใ“ใจใงใ™ใ€‚ๆˆ‘ใ€…ใฎ็Šถๆณใงใฏใ€ใ“ใ‚Œใฏไธๅฏ่ƒฝใงใ™ใ€‚ใชใœใชใ‚‰ใ€ใใ‚Œใฏใ€ๆ˜Žใ‚‰ใ‹ใซ้›†็ด„ใฎ้ƒจๅˆ†ใ‚’็ ดๅฃŠๅฏ่ƒฝใงใ‚ใ‚‹ใจใ„ใ†ไบ‹ๅฎŸใŒใ‚ใ‚‹ใŸใ‚ใงใ™ใ€‚ๅพŒ็ถšใฎๅ‡ฆ็†ใงใ€ใใฎ้ƒจๅˆ†ใธๅˆฐ็€ใ—ใ‚ˆใ†ใจใ—ใฆใ‚‚ nsnull ใŒ่ฟ”ใ‚Šใพใ™ใ€‚ๆ™‚ใ€…ใ€ๅผฑใ„ใƒใ‚คใƒณใ‚ฟใƒผใ‚’้€šใ˜ใŸ QueryInterface ใŒใ€Œๆœฌๅฝ“ใฎใ€ใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใ‚’่ฟ”ใ™ใงใ—ใ‚‡ใ†ใ€‚ใใ—ใฆๆ™‚ใ€… nsnull ใ‚’่ฟ”ใ™ใฎใงใ™ใ€‚ใใ‚Œใฏใ€ๅ˜ใซ COM ใ‚’ๅฃŠใ™ใ“ใจใซใชใ‚Šใพใ™ใ€‚

ใ“ใฎใ‚ˆใ†ใซใ€ๅผฑใ„ๅ‚็…งใŒๅฏพ่ฑกใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใธใจ้›†็ด„ใ•ใ‚Œใชใ„ใฎใฏๆ˜Žใ‚‰ใ‹ใงใ™ใ€‚ใใ‚ŒใŸใ‚ใ€ใใ‚Œใ‚‰ใฎ้–“ใ‚’ๅ‹•ใใฎใซ QueryInterface ใ‚’ไฝฟใ†ใ“ใจใฏใงใใพใ›ใ‚“ใ€‚ใ“ใ‚Œใฏใ€ใ‚ˆใ‚Šไพฟๅˆฉใซๆ„Ÿใ˜ใ‚‰ใ‚Œใ‚‹ใจๆ€ใ„ใพใ™ใŒใ€ใ‚ฐใƒญใƒผใƒใƒซใƒซใƒผใƒใƒณใฎ NS_GetWeakReference ใ‚’ไฝฟใ†ใจใ€ๅฏพ่ฑกใฎใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใ‹ใ‚‰ๅผฑใ„ๅ‚็…งใ‚’ๅพ—ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ใใ—ใฆใ€nsIWeakReference::QueryReferent ใŒใ€้€†ใฎๆ–นๅ‘ใซๅฏพใ—ใฆ QueryInterface ใจๅŒใ˜ๆฉŸ่ƒฝใ‚’ๆไพ›ใ—ใพใ™ใ€‚ไป˜ใ‘ๅŠ ใˆใ‚‹ใจใ€็พๅœจใ€nsCOMPtr ใฏใ€ๆ–ฐใ—ใ„ใ‚ญใƒผใฎ do_QueryReferent ใ‚’ใ‚ตใƒใƒผใƒˆใ™ใ‚‹ใ‚ˆใ†ใซใชใ‚Šใ€ไบบ็”Ÿใ‚’ใ„ใใถใ‚“ใ‚ทใƒณใƒ—ใƒซใซใ—ใฆใใ‚Œใฆใ„ใพใ™ใ€‚

ใ‚ฏใƒฉใ‚นใŒๅผฑใ„ๅ‚็…งใ‚’ใ‚ตใƒใƒผใƒˆใ™ใ‚‹ใ‚ˆใ†ใซใ™ใ‚‹ใซใฏใฉใ†ใ™ใ‚Œใฐใ‚ˆใ„ใงใ—ใ‚‡ใ†ใ‹๏ผŸ

ๅ˜ใซ nsSupportsWeakReference ใ‚’็ถ™ๆ‰ฟใ™ใ‚‹ใ ใ‘ใงใ™ใ€‚ใƒŸใƒƒใ‚ฏใ‚นใ‚คใƒณใ‚ฏใƒฉใ‚นใŒใ™ในใฆใฎไฝœๆฅญใ‚’่กŒใฃใฆใใ‚Œใพใ™ใ€‚ใใ—ใฆใ€ใ‚ใชใŸใฎ QueryInterface ใ‚’้ฉๅฎœๅค‰ใˆใฆใใ ใ•ใ„ใ€‚ไพ‹ใˆใฐใ€

//...
#include "nsWeakReference.h"

class nsFooย : public nsIFoo, ..., public nsSupportsWeakReference { ... };


// ...if you used the table macros to implement |QueryInterface|, add an entry

NS_INTERFACE_MAP_BEGIN(nsFoo)
  // ...
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  // ...
NS_INTERFACE_MAP_END


// ...if you used a |NS_IMPLE_QUERYINTERFACEn| macro, move up to the next higher one and add a term

NS_IMPL_QUERYINTERFACEn+1( ...,nsISupportsWeakReference)


// ...if you implemented |QueryInterface| by hand, add a clause

NS_IMETHODIMP
nsFoo::QueryInterface( REFNSIID aIID, void** aInstancePtr )
  {
    // ...
    else if ( aIID.Equals(nsCOMTypeInfo<nsISupportsWeakReference>::GetIID()) )
      *aInstancePr = NS_STATIC_CAST(nsISupportsWeakReference*, this);
    // ...
  }

ไปฃๆ›ฟๆ‰‹ๆฎต

This technique is useful, but in situations where you need this, there are two alternatives which you may want to consider:

  • You might hold an owning reference, but arrange to Release it out-of-band; this must be before the destructor, which would otherwise never be called.
  • You might hold a raw pointer (without AddRefing and Releaseing it), and avoid using it in cases where it might dangle.

ๅ‚่€ƒ่ณ‡ๆ–™

ๅŽŸๆ–‡ๆ›ธใฎๆƒ…ๅ ฑ

  • ่‘—่€…: Scott Collins
  • ๆœ€็ต‚ๆ›ดๆ–ฐๆ—ฅ: September 23, 2000
  • ่‘—ไฝœๆจฉ: Portions of this content are ยฉ 1998โ€“2007 by individual mozilla.org contributors; content available under a Creative Commons license | ่ฉณ็ดฐ