0

所以我有一些 C++ 类,它们使用映射和键类作为一种数据结构。在我的插入方法中,我使用典型的 map.insert。我希望这个函数返回一个指针,这样我就可以在插入的元素中修改一些值(不是用于比较的值)。所以我想知道这是否安全..

template<typename T>
NodeT<T> *  TreeT<T>::
MakeNode(PointT point)
{
  NodeT<T> * prNode = new NodeT<T>;

    //set the contents for the node
  prNode->SetNode(point, m_dTolerance);


  //Create the key class using the 
  VectorKey key(point, m_dTolerance);

  //Store the key,node as a pair for easy access 
  return_val = m_tree.insert( pair<VectorKey, NodeT<T> >(key, *prNode) );
  if (return_val.second == false)
    //if return_val.second is false it wasnt inserted
    prNode = NULL;
  else
   //it was inserted, get a pointer to node
    prNode = &(return_val.first->second); //is this safe if I plan to use it later?

  return prNode;

}

我似乎学会了一种艰难的方式,即我的原始指针(我用 new 创建的那个)在插入后指向错误的元素。谁能告诉我这是为什么?所以我使用 return_val 迭代器来获取正确的指针。我有点不想返回迭代器,但如果它更安全,那么我会......

谢谢!

4

3 回答 3

2

您的代码中似乎存在指针和值的问题。首先,您在堆上分配一个对象(使用新节点),然后使用该对象的副本在您的地图中疼痛。PS。然后你永远失去原始对象,因为不释放内存,这会导致内存泄漏。

在您的情况下-它是无效的,因为您返回指向可以随时删除的对象的指针(例如,下次您向地图添加内容时,地图决定重新分配它的树,因此它将对象复制到不同的地方)。将指针存储为映射值可以防止这种情况。从地图中移除对象和移除地图本身时,您需要记住的唯一一件事是清除它们。处理该问题的简单方法是使用智能指针(例如 boost::shared_ptr)或智能地图类(例如 boost::ptr_map)。

要解决这个问题 - 在任何地方使用指针(将指针存储为映射值)。这样 - 您将能够从此函数返回指针并且它将是有效的。因此,只需将您的地图转到 map*>,这应该可以解决您的大部分问题。从地图上删除对象时不要伪造删除对象。

于 2013-06-07T16:14:49.407 回答
1

这个代码示例很有趣,因为它包含一些错误或要避免的地方。

执行

最重要的事情已经说了(主要是博戈尔特):

  • 您正在泄漏内存,因为NodeT<T>从堆中分配并且永远不会再次释放它,因为map将分配对象的副本,而不是指针。实际上,您指定为 parameter *prNode,而不是prNode
  • 您使用堆来分配对象(将被复制到 中map),但您假设您总是分配对象。尽管这将是最有可能的情况,但这并不总是正确的:new运算符将返回 null 或抛出bad_alloc异常。代码不处理它。
  • 无论如何,您在不需要时使用堆。(你会看到问题是因为你引人入胜的)。您可以只在堆栈中创建对象,然后插入到地图中,避免以前的问题并输入更少的代码。

设计

  • 该函数返回指向地图中元素的指针。根据程序,这可能是安全的。但是,如果在从地图中删除对象时代码引用指针会发生什么?更好的是,如果您要返回指针,请不要返回原始指针。请改用智能指针(shared_ptr在这种情况下)。使用shared_ptr你不会对对象的生命产生任何问题。
  • 使用智能指针的其他原因:因为插入到地图中意味着元素的副本,所以您要求NodeT<T>:它必须是可复制构造的。可能这个要求对性能并不重要,但可能在其他情况下复制对象有缺点。如果您使用智能指针(或boost::ptr_map),则该对象将只创建一次并且不会被复制。

风格

只是一些建议,但不是太重要:

  • 而是键入pair<VectorKey, NodeT<T> >(key, *prNode),键入make_pair(key, *prNode)。代码更紧凑,打字更清晰。
于 2013-06-10T07:41:24.837 回答
0

好吧,我会说这取决于您的地图是否比任何可以使用(和存储)指针的东西更长寿。

如果是,(即,它在某种单例中),您可以使用它,但无论如何都不是很安全,因为任何代码都可以删除指针。

最好的选择是在 mapn 中存储 boost::shared_ptr (或 std:: 自 c++11 以来)而不是原始指针,并在插入后仅返回一个 weak_ptr 。

这样一来,您就可以确定,只要地图保留指针,其他代码就无法删除您的指针,并且没有人可以使用已从地图中删除的指针。

于 2013-06-07T16:06:03.230 回答