C++ C++;:在深度复制中更新指针(高效)

C++ C++;:在深度复制中更新指针(高效),c++,pointers,deep-copy,C++,Pointers,Deep Copy,我的问题最好用一个代码示例来说明,所以让我们从以下内容开始: class Game { // All this vector does is establish ownership over the Card objects // It is initialized with data when Game is created and then is never // changed. vector<shared_ptr<Card> > m

我的问题最好用一个代码示例来说明,所以让我们从以下内容开始:

class Game
{
    // All this vector does is establish ownership over the Card objects
    // It is initialized with data when Game is created and then is never
    // changed.
    vector<shared_ptr<Card> > m_cards;

    // And then we have a bunch of pointers to the Cards.
    // All these pointers point to Cards from m_cards.
    // These could have been weak_ptrs, but at the moment, they aren't
    vector<Card*> m_ptrs;

    // Note: In my application, m_ptrs isn't there, instead there are
    // pointers all over the place (in objects that are stored in member
    // variables of Game.
    // Also, in my application, each Card in m_cards will have a pointer
    // in m_ptrs (or as I said, really just somewhere), while sometimes
    // there is more than one pointer to a Card.
}
类游戏
{
//这个向量所做的就是建立卡对象的所有权
//它在游戏创建时用数据初始化,然后再也不会被初始化
//变了。
向量m_卡;
//然后我们有一堆指向卡片的指针。
//所有这些指针都指向m_卡中的卡。
//这些可能是薄弱的PTR,但目前并非如此
向量m_-ptrs;
//注意:在我的应用程序中,m_ptrs不存在,而是存在
//到处都是指针(在存储在成员中的对象中
//游戏变量。
//另外,在我的应用程序中,m_卡中的每个卡都有一个指针
//在m_ptrs(或者如我所说,真的只是某个地方),而有时
//指向卡片的指针不止一个。
}
现在我要做的是制作这个游戏类的深度副本。我制作了一个新的向量,其中包含新的共享ptr,它指向新的卡对象,这些卡对象是原始卡对象的副本。这一部分很简单

然后问题开始了,m_PTR的指针应该更新为指向m_卡中的卡,这不是简单的任务

我能想到的唯一方法是创建一个映射并在复制m_卡时填充它(使用
map[oldPtr]=newPtr
),然后使用它来更新m_ptr。然而,这只是
O(m*log(n))
m=m_ptrs.size();n=m_卡.size()
)。由于这将是一个非常常规的操作*我希望能有效地执行此操作,我觉得在
O(m)
中使用自定义指针应该是可能的。但是,我似乎找不到一种有效的方法来执行此操作。有人这样做吗

*它被用来为人工智能创建一个测试平台,让它“尝试”不同的动作


编辑:我想补充一点关于接受答案的内容,因为我还没有回答。我一直在等待,直到我回到这个项目(因为我在这个项目上做了太多的工作,所以我走上了一条岔路——如果你是为了乐趣而做的,那就必须保持乐趣),所以我可能需要一段时间才能接受答案。不过,我会在某个时候接受答案,所以不要担心:P


编辑NR2:我还没有回到这个项目。现在,我正在考虑只取
O(m*log(n))
way,不要抱怨,然后再看看是否需要更快。然而,由于我最近花了一些时间学习我的模式,我也在想,我真的需要在某个时候重构这个项目。哦,我可能会花一些时间用我掌握的所有新知识来解决这个问题。因为没有一个回答是“坚持使用hashmap,看看它是否真的需要更快”(如果有,我会非常失望,因为这不是我问题的答案),我会推迟选择答案,直到我回到这个项目



编辑nr 3:我仍然没有回到这个项目。更准确地说,它已经被无限期搁置。我非常确定我不会对
O(m*log(n))太低头
现在,如果发现问题,也许以后再看。但是,这不是我问题的好答案,因为我明确要求提高性能。我不想让答案不再被接受,我选择了最有用的答案并接受了它。

将指针存储为索引。 正如你所说,它们都指向m_卡片,这是一个可以被索引的向量(这是正确的英语吗?)。 或者只在存储时这样做,然后在加载时将它们转换回指针。
或者您可能会考虑通常使用索引而不是指针。

将卡片元素保留为索引而不是指针怎么样:

vector<int> m_indexes; ... Card* ptr = &m_cards[m_indexes[0]]; 向量m_指数; ... 卡片*ptr=&m_卡片[m_索引[0]];
带有索引的向量可以不加更改地复制。

我最近遇到了非常类似的问题:克隆由指针和std::Vector实现的类内部结构作为对象存储

首先(与问题无关),我建议要么使用智能指针,要么使用简单结构。在你的例子中,这意味着使用
向量m_ptrs
而不是原始指针更有意义

关于问题本身-另一个可能的解决方法是在复制构造函数中使用指针差异。我将为对象向量演示它,但使用共享指针将使用相同的原理,唯一的区别是复制m_卡(如果需要对象克隆,不应简单地使用赋值,而应逐个元素复制
m_卡)

非常重要的一点是,该方法仅适用于保证存储元素的容器(向量、数组)

另一个非常重要的时刻是
m_ptr
元素应仅表示内部
结构,即它们必须仅指向内部
m_卡
元素

// assume we store objects directly, not in shared pointers
// the only difference for shared pointers will be in
// m_cards assignment
// and using m_cards[...].get() instead of &m_cards[...]
vector<Card> m_cards;
vector<Card*> m_ptrs;
//假设我们直接存储对象,而不是存储在共享指针中
//共享指针的唯一区别在于
//m_卡分配
//并使用m_卡[…]。get()而不是&m_卡[…]
向量m_卡;
向量m_-ptrs;
在这种情况下,可以通过使用指针算术(使用线性时间)轻松计算指针数组。在这种情况下,复制构造函数将如下所示:

Game::Game(const Game &rhs) {
  if (rhs.m_cards.empty())
    return;

  m_cards = rhs.m_cards;

  // if we have vector of shared pointers
  // and we need vector of pointers to objects clones
  // something like this should be done
  // for (auto p: rhs.m_cards) {
  //   // we must be certain here that dereferencing is safe,
  //   // i. e. object must exist. If not, additional check is required.
  //   // copy constructor will be called here:
  //   m_cards.push_back(std::make_shared<Card>(*p));
  // }

  Card *first = &rhs.m_cards[0];
  for (auto p: rhs.m_ptrs) {
    m_ptrs.push_back(&m_cards[p - first]);
  }
}
Game::Game(const-Game和rhs){
if(rhs.m_cards.empty())
返回;
m_卡=rhs.m_卡;
//如果我们有共享指针的向量
//我们需要指向对象克隆的指针向量
//应该这样做
//用于(自动p:rhs.m_卡){
////在这里,我们必须确定取消引用是安全的,
////即对象必须是