1

の実装がどのように機能するかを理解したいstd::function。簡単にするために、引数のない移動のみの関数を考えてみましょう。

std::functionは、典型的な型消去手法を使用してターゲットの型を消去することを理解しています。

template<class Result>
struct function
{
  public:
    template<class Function>
    function(Function&& f)
      : f_(std::make_unique<callable_base>(std::forward<Function>(f)))
    {}

    // XXX how to implement constructor with allocator?
    template<class Alloc, class Function>
    function(const Alloc& alloc, Function&& f);

    Result operator()() const
    {
      return (*f_)();
    }

  private:
    struct callable_base
    {
      virtual Result operator()() const = 0;
      virtual ~callable_base(){}
    };

    template<class Function>
    struct callable
    {
      mutable Function f;

      virtual Result operator()() const
      {
        return f;
      }
    };

    // XXX what should the deleter used below do?
    struct deleter;

    std::unique_ptr<callable_base, deleter> f_;
};

カスタム割り当てをサポートするために、このタイプの機能を拡張したいと思います。アロケータの型を消去する必要がありますが、std::unique_ptr. に指定されたカスタム デリーターは、ストレージの割り当てを適切に解除できるように、コンストラクターに指定されたunique_ptrの具体的な型を知る必要があります。Function別のunique_ptrタイプを使用してデリータを消去することもできますが、その解決策は循環的です。

callable<Function>それ自体を解放する必要があるようです。それを行う正しい方法は何ですか?のデストラクタ内で割り当てを解除callable<Function>すると、メンバーがまだ生きているため、早すぎるように思えます。

4

3 に答える 3

2

メモリ管理のために提供されたアロケータのみに依存して、移植可能な方法でこれを行うことは可能だとは思いません。

の実装を探していました。これは、デリータとアロケータの型消去もstd::shared_ptrサポートしているためです (オーバーロード 6 を参照) 。スケッチの実装では、これらのコピーを格納する補助オブジェクトが使用されていますが、このオブジェクトは割り当てられています。を使用して解放し、提供されたアロケータとデリータをバイパスします。operator newoperator delete

格納されているアロケータ (コピーの作成元) と格納されているオブジェクトの両方を解放するために、アロケータの一時コピー (スタック上) を使用することを考えていました。new問題は、 /を使用せずに、タイプがわからない場合にコピーを取得するにはどうすればよいかということdeleteです。残念ながら、共分散はこれによって除外されます (ポインターを返す必要があります)。

そして今、非標準の解決策にたどり着きます:allocaまたは可変長配列の使用に慣れている場合は、スタック上に十分なサイズのメモリ領域を作成し、格納されたアロケータにそれ自体のコピーを作成させるデリータを用意できます。その記憶。このスタックに割り当てられた (自動保存期間) コピーは、保存されたアロケーターと保存されたオブジェクトの両方を解放し、最終的に削除機能によって破棄されます (これはすべてのポイントであり、アロケーターの具体的な型を認識していません)。 )。大まかなスケッチ:

struct aux_base {
  // also provide access to stored function
  virtual size_t my_size(void) const = 0;
  virtual aux_base * copy_in(void * memory) const = 0;
  virtual void free(void * ptr) = 0;
  virtual ~aux_base() {}
};

template<class Alloc, class Function>
struct aux : public aux_base {
  // Store allocator and function here

  size_t my_size(void) const {
    return sizeof(*this);
  }
  aux_base * copy_in(void * memory) const {
    // attention for alignment issues!
    return new (memory) aux(*this);
  }
  void free(void * ptr) {
    aux * stored = reinterpret_cast<aux *>(ptr);
    // do your stuff
  }
};

void deleter_for_aux(aux_base * ptr) {
  char memory[ptr->my_size()];
  aux_base * copy = ptr->copy_in(memory);
  copy->free(ptr);
  copy->~aux_base(); // call destructor
}

とはいえ、提供されたアロケータ以外の別の動的メモリ ソースに依存せずに、標準 C++ でこれを行う方法があれば、私はそれについて知りたいです! :)

于 2016-03-12T15:46:21.643 に答える