所以我有一些C ++类使用map和key类来处理某种数据结构。在我的插入方法中,我使用典型的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迭代器来获取正确的指针。我有点不想要返回迭代器但是如果它更安全那么我会...
谢谢!
答案 0 :(得分:2)
您的代码中似乎有指针和值的麻烦。首先在堆上分配一个对象(使用新节点) 然后使用该对象的副本在地图中疼痛。 PS。然后你永远松开原始物体,因为没有释放内存导致内存泄漏。
在您的情况下 - 它是无效的,因为您返回指向对象的指针,可以随时删除(例如,下次向地图添加内容并且地图决定重新分配它的树,因此它会将对象复制到不同的地方)。 将指针存储为映射值会阻止这种情况。在从地图中删除对象以及删除地图本身时,您唯一需要记住清除它们。 处理它的简单方法是使用智能指针(例如boost :: shared_ptr)或智能地图类(例如boost :: ptr_map)。
要解决此问题 - 在任何地方使用指针(将指针存储为地图值)。 这样 - 您将能够从此函数返回指针,它将是有效的。 所以只需将地图转换为地图*&gt;这应该解决你的大多数问题。 从地图上删除对象时,不要伪造删除对象。
答案 1 :(得分:1)
此代码示例很有趣,因为包含一些错误或要避免的错误。
<强>实施强>
最重要的事情已经说过(主要是博格特):
NodeT<T>
并且永远不会再释放它,因为map
将分配对象的副本,而不是指针。实际上,您指定为参数*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)
。代码更紧凑,更清晰,打字更少。答案 2 :(得分:0)
好吧,我会说这取决于你的地图是否比可以使用(并存储)指针的任何东西活着更久。
如果是,(即,它是某种单身),你可以使用它,但不管怎样都不安全,因为任何代码都可以删除指针。
最好的选择是存储boost :: shared_ptr(或std :: since c ++ 11)而不是mapn中的原始指针,并在插入后仅返回weak_ptr。
这样,只要地图保存了指针就确定没有其他代码可以删除指针,并且没有人可以使用已从地图中删除的指针。