6

ここで最初に説明したのと同様のシステムを実装しようとしています。つまり、実行時にオブジェクトの動作を変更するために vtable の変更を (悪用) 使用することです。これは、私が取り組んでいる C++ プロジェクトで効率的な型ジェネリック ラッパーを作成する試みの一部です。

例では、アクセスできない場合は、次のように使用して vtablememcpy()thisポインターをコピーします。

void setType( const DataType& newType )
{
    memcpy( this, &newType, sizeof(DataType) );
}

ただし、この方法には問題があります。vtable のコピー元となるターゲット クラスのオブジェクトがなく、作成する必要がないタイプもあります。

そのクラスのオブジェクトなしで、特定のクラスのオブジェクトに埋め込まれた vtable にアクセスする方法はありますか?

ある程度移植性があれば望ましいのですが、私はこれがコンパイラ固有であることを大部分辞任しました。そのため、他に選択肢がない場合は、GCC/G++ のみの方法が受け入れられます。また、かなり標準的な OS とアーキテクチャでこれを構築することだけに関心があると仮定しましょう。

私はC++ 11を使用していますが、それが何らかの形でこれを支援する必要があります。

編集:完全に明確にしたいのですが、この種の行動がどれほど危険であるかを知っています. 私は、このアイデアと、おそらく非常に管理された状況でのその狭いアプリケーションに興味がありますが、私の紹介が示唆するものにもかかわらず、それが製品ソフトウェアにとって良いアイデアであるということよりも興味があります。

4

1 に答える 1

4
struct many_vtable {
  void(*dtor)(void*);
  void(*print)(void const*,std::ostream&);
};
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag = {};

template<class T>
many_vtable const* make_many_vtable(tag_t<T>){
  static const many_vtable retval = {
    // dtor
    [](void* p){
      reinterpret_cast<T*>(p)->~T();
    },
    // print
    [](void const*p, std::ostream& os){
      os<<*reinterpret_cast<T const*>(p);
    }
  };
  return &retval;
}
struct many {
  many_vtable const* vtable=nullptr;
  std::aligned_storage_t<100, alignof(double)> buff;
  void clear(){if(vtable) vtable->dtor(&buff);vtable=nullptr;}
  ~many(){ clear(); }
  many()=default;
  many(many const&)=delete; // not yet supported
  many& operator=(many const&)=delete; // not yet supported

  explicit operator bool()const{return vtable!=nullptr;}

  template<class T,class...Args>
  void emplace(Args&&...args){
    static_assert(alignof(T) <= alignof(double), "not enough alignment");
    static_assert(sizeof(T) <= 100, "not enough size");
    clear();
    ::new((void*)&buff) T(std::forward<Args>(args)...);
    vtable=make_many_vtable(tag<T>);
  }
  friend std::ostream& operator<<(std::ostream& os, many const&m){
    if(!m.vtable) return os;
    m.vtable->print(&m.buff, os);
    return os;
  }
};

これは手動の vtable 設計です。ストリームに出力できる double 未満のアラインメントを持つ最大 100 バイトのデータを格納できます。

より多くの(または異なる)操作への「消去」は簡単です。たとえば、別の多数にコピー/移動できること。

標準に違反しておらず、リンクされた例と同様のオーバーヘッドがあります。

many m;
m.emplace<int>(3);
std::cout << m << '\n';
m.emplace<double>(3.14);
std::cout << m << '\n';

実例

基本的に vtable の概念を手動で再実装しているため、これは手動の vtable です。

于 2016-03-04T17:54:44.533 に答える