C++ で所有者オブジェクトのアドレスを知るにはどうすればよいですか?
-
22-08-2019 - |
質問
オブジェクトが破棄されたときにさまざまなホルダーに通知するために他のオブジェクトで使用する Notifier クラスを C++ で作成したいと考えています。
template <class Owner>
class Notifier<Owner> {
public:
Notifier(Owner* owner);
~Notifier(); // Notifies the owner that an object is destroyed
};
class Owner;
class Owned {
public:
Owned(Owner* owner);
private:
Notifier<Owner> _notifier;
};
ここで言いたいのは、高密度で複雑なオブジェクト グラフがあるため、所有されているオブジェクトのアドレスをノーティファイアに保存することは避けたいということです。所有するオブジェクトのアドレスを、自身のアドレスとコンパイル時に計算されるオフセットから推測できるように、ノーティファイア クラスを変更する方法はありますか?
また、どのオブジェクトでも、おそらく同じクラスからの複数の「所有者」に通知する必要がある場合があることにも注意してください。
ありがとう。
解決
またはこのような何かます:
あなたの通知を継承し、テンプレートパラメータとして所有追加します。そして、あなたは通知内部で利用可能な所有メソッドを持つことができます:
template < class Owner , class Owned >
class Notifier
{
public:
Notifier(Owner* owner)
{}
Owned * owned()
{ return static_cast< Owned * >( this ); }
~Notifier()
{
// notify owner with owned()
}
};
class Owner
{};
class Owned : public Notifier< Owner , Owned >
{
public:
Owned( Owner * owner ) : Notifier< Owner , Owned >( owner )
{}
};
他のヒント
思います ルコビーチ hackところなどは動作保証対象外とさせていのだが、ここでの思い 今からとっても待ち遠しいですこ.
いレイアウトのようなご説のようになります:
template <class Owner>
class Notifier<Owner> {
public:
Notifier(Owner* owner);
~Notifier(); // Notifies the owner that an object is destroyed
};
class Owner;
class Owned {
public:
Owned(Owner* owner);
private:
Notifier<Owner> _notifier;
};
の場合 _notifier
知っての名称、その計算 Owned
'sアドレスのようなこと(実行され Notifier
's"のコンストラクタ):
Owned *p = reinterpret_cast<Owned *>(reinterpret_cast<char *>(this) - offsetof(Owned, _notifier));
基本的には現_notifierは一定の内のオフセット所有のクラスです。そのためのアドレスの所有等 _notifier
'sアドレスマイナスなことを相殺するものとする。
再び、これが定義されていない動作するのかをお勧めることが可能になれます。
ファさんの答え 良いスタートです。ただし、同じタイプの所有者が複数存在するという問題は解決されません。解決策の 1 つは、通知者に単一の所有者の代わりに所有者のリストを保存させることです。アイデアを示すための簡単な実装を次に示します。
template <typename Owner, typename Owned>
class Notifier
{
protected:
Notifier()
{}
// Constructor taking a single owner
Notifier(Owner & o)
{
owners.push_back(&o);
}
// Constructor taking a range of owners
template <typename InputIterator>
Notifier(InputIterator firstOwner, InputIterator lastOwner)
: owners(firstOwner, lastOwner) {}
~Notifier()
{
OwnerList::const_iterator it = owners.begin();
OwnerList::const_iterator end = owners.end();
for ( ; it != end ; ++it)
{
(*it)->notify(static_cast<Owned*>(this));
}
}
// Method for adding a new owner
void addOwner(Owner & o)
{
owners.push_back(&o);
}
private:
typedef std::vector<Owner *> OwnerList;
OwnerList owners;
};
次のように使用できます。
class Owner;
class Owned : public Notifier<Owner, Owned>
{
typedef Notifier<Owner, Owned> base;
//Some possible constructors:
Owned(Owner & o) : base(o) { }
Owned(Owner & o1, Owner & o2)
{
base::addOwner(o1); //qualified call of base::addOwner
base::addOwner(o2); //in case there are other bases
}
Owned(std::list<Owner*> lo) : base(lo.begin(), lo.end()) { }
};
さまざまなタイプの所有者がいる場合、このソリューションは使用がかなり困難になる可能性があります。この場合、ブースト メタプログラミング ライブラリ (MPL, 融合)、これを使用すると、次のようなことを実行できるコードが完成する可能性があります。
class Owned : public Notifier<Owned, OwnerType1, OwnerType1, OwnerType2>
{
Owned(OwnerType1 & o1, OwnerType1 & o2, OwnerType2 & o3)
: base(o1,o2,o3)
};
ただし、このソリューションの実装には、前のソリューションよりも少し時間がかかります。
ソリューションの一部は、通知から継承を所有していることであろう。この方法では、破壊されたオブジェクトのアドレスは、単に「この」...
class Owned : public Notifier<Owner> {
public:
Owned(Owner* owner)
: Notifier<Owner>(owner)
{}
};
しかし、同じクラスから複数の「所有者」をどのように扱いますか?どのようにして「同じクラスのから数回を継承することができますか?
おかげhref="https://stackoverflow.com/questions/709790/how-can-i-know-the-address-of-owner-object-in-c/709996#709996"> FA年代をに答えて、ここで私が探していたソリューションは、次のとおりです。
#include <iostream>
template <class Owner, class Owned, int = 0>
class Notifier {
public:
Notifier(Owner* owner)
: _owner(owner)
{}
~Notifier() {
_owner->remove(owned());
}
Owned * owned(){
return static_cast< Owned * >( this );
}
private:
Owner* _owner;
};
class Owner {
public:
void remove(void* any) {
std::cout << any << std::endl;
}
};
class Owned : public Notifier<Owner,Owned,1>, Notifier<Owner,Owned,2> {
public:
Owned(Owner* owner1, Owner* owner2)
: Notifier<Owner,Owned,1>(owner1)
, Notifier<Owner,Owned,2>(owner2)
{}
};
int main() {
std::cout << sizeof(Owned) << std::endl;
Owner owner1;
Owner owner2;
Owned owned(&owner1, &owner2);
std::cout << "Owned:" << (void*)&owned << std::endl << std::endl;
}
ありがとうございます。
私は非常にそれを疑います。 Notifierは、それが組成物中で使用されていることを知ってする方法はありません。私は何場合は、
class Foo
{
private:
Notifier _a, _b, _c;
}
私も間違って証明するのが大好きですが、私は実際にそれが明示的に通知するより多くの情報を与えることなくなんとかだ疑います。