微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

连续分配两个对象从第二个地址中获取第一个创建后,不要静态知道第二个对象的类型

如何解决连续分配两个对象从第二个地址中获取第一个创建后,不要静态知道第二个对象的类型

我正在尝试编写一个在单个内存块中连续分配两个对象的工厂。然后,给定第二个对象的地址,我需要获取一个

更复杂的是,第二个对象可以是从给定基类派生的任何类型。

这里有一些代码显示我需要的东西:

// the second object in memory is always a Node
struct Node { virtual ~Node()=default; };
struct X : Node {};

struct First {}; // first object in memory

// I need to do this:
int main() {
    // factory creates and manages Nodes with an associated First object
    Factory factory;
    // creating a Node
    X* node = factory.make<X>();
    // retrieving the First object associated to node
    First* first = getFirst( node );
}

这里是我(失败的)实施尝试。

#include <vector>
#include <memory>

struct Factory {
    std::vector< std::unique_ptr<???> > memory; // what should its type be?
    
    template<typename T> T* make() {
        struct Block { First first; T second; };
        auto blockPtr = std::make_unique<Block>();
        auto& block = *blockPtr;
        memory.push_back( std::move(blockPtr) );
        return block.second;
    }
    First* getFirst( Node* node ) {
        // what do I do here?
    }
};

我如何在 C++ 中正确实现它?

任何标准都可以,最好是 C++17,但 C++20 也可以。

我能够以其他方式实现工厂的行为。例如 通过使用 std::unordered_map<Node*,First> 将 First 关联到 Node。但我认为应该可以将两个对象保存在同一个内存块中,并使用指针算法访问它们。

解决方法

您希望将派生自 Node 但在其他方面完全任意的类与 First 的实例相关联,因此我们需要创建一个模板化的类来将它们保持在一起:

template <typename T>
class Block
{
  static_assert(std::is_base_of_v<Node,T>);
  First _first;
  T _instance;
};

鉴于我们不知道 T 的对齐方式,我们通常无法知道 _first_instance 之间的偏移量,因此只能使用指针算法来查找 &_first来自 &_instance 是不可能的。 如果您只是想将它们放在一起并且可以通过从关联容器中查找来找到 &_first,您可以使用以下方法:

#include <memory>
#include <map>
#include <iostream>

class Node
{
public:
  virtual ~Node() = default;
};

class First {};



class I_Block
{
public:
  virtual First * get_first() = 0;

  virtual ~I_Block() = default;
};


template <typename T>
class Block : public I_Block
{
public:
  static_assert(std::is_base_of_v<Node,T>,"T must be derived from Node");

  Block()
  : _first(),_instance()
  { }

  First * get_first() override
  {
    return &_first;
  }

  T * get_instance()
  {
    return &_instance;
  }
protected:
private:
  First _first;
  T _instance;
};



class Factory
{
public:
  Factory() = default;

  template <typename T>
  T * make()
  {
    auto block = std::make_unique<Block<T>>();
    T * result = block->get_instance();
    _memory.emplace(result,std::move(block));
    return result;
  }

  First * get_first(Node const * node) const
  {
    auto block = _memory.find(node);
    if (block == _memory.end()) throw 123; // node not found
    return block->second->get_first();
  }

protected:
private:
  std::map<Node const *,std::unique_ptr<I_Block>> _memory;
};






class Alpha : public Node
{
public:
  Alpha() = default;
protected:
private:
};

class Beta : public Node
{
public:
  Beta() = default;

  virtual void doit() { }
protected:
private:
  double _value;
};



int main()
{
  Factory factory;

  Alpha * alpha = factory.make<Alpha>();
  std::cout << "&alpha = " << alpha << std::endl;
  std::cout << "&first(alpha) = " << factory.get_first(alpha) << std::endl;

  Beta * beta = factory.make<Beta>();
  std::cout << "&beta = " << beta << std::endl;
  std::cout << "&first(beta) = " << factory.get_first(beta) << std::endl;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。