10

从 a 返回指向std::map::find数据的指针并使用它而不是获取数据的副本是否危险?

目前,我得到一个指向我的地图条目的指针,并将其传递给另一个函数以显示数据。我担心项目移动导致指针无效。这是一个合法的担忧吗?

这是我的示例函数:

MyStruct* StructManagementClass::GetStructPtr(int structId)

{
    std::map<int, MyStruct>::iterator foundStruct;
    foundStruct= myStructList.find(structId);
    if (foundStruct== myStructList.end())
    {
        MyStruct newStruct;
        memset(&newStruct, 0, sizeof(MyStruct));
        myStructList.structId= structId;
        myStructList.insert(pair<int, MyStruct>(structId, newStruct));

       foundStruct= myStructList.find(structId);
   }

   return (MyStruct*) &foundStruct->second;

}

4

4 回答 4

9

毫无疑问,返回迭代器比返回指针更典型,尽管它可能没什么区别。

就剩余有效而言:地图迭代器保持有效,直到/除非它所引用的项目被从地图中删除/删除。

当您在地图中插入或删除某些其他节点时,可能会导致地图中的节点被重新排列。这是通过操作节点之间的指针来完成的,因此它会更改其他节点包含指向您关心的节点的指针的内容,但不会更改该特定节点的地址或内容,因此指向该节点的指针/迭代器仍然有效。

于 2013-05-08T14:09:00.960 回答
3

只要您、您的代码和您的开发团队了解 std::map 值的生命周期(在 、 、 或 之后有效,在、、或insert之后无效),那么使用、、或都是有效的。此外,如果返回始终保证存在,则或也是有效的。eraseclearassignoperator=iteratorconst_iterator::mapped_type*::mapped_type const*::mapped_type&::mapped_type const&

至于明智,我更喜欢const版本而不是可变版本,我更喜欢引用而不是指针而不是迭代器。

返回迭代器与指针是不好的:

  • 它公开了一个实现细节。
  • 使用起来很尴尬,因为调用者必须知道取消引用迭代器,结果是 std::pair,然后必须调用.second以获取实际值。
    • .first是用户可能不关心的关键。
  • 确定迭代器是否无效需要了解::end(),而这对调用者来说显然是不可用的。
于 2013-05-08T14:19:10.970 回答
2

这并不危险——只要迭代器或引用有效,指针就会保持有效。

但是,在您的特定情况下,我认为这无论如何都不是正确的事情。您的函数无条件地返回结果。它从不返回 null。那么为什么不返回参考呢?

此外,对您的代码的一些评论。

std::map<int, MyStruct>::iterator foundStruct;
foundStruct = myStructList.find(structId);

为什么不将声明和赋值合并到初始化中呢?然后,如果你有 C++11 支持,你可以写

auto foundStruct = myStructList.find(structId);

然后:

  myStructList.insert(pair<int, MyStruct>(structId, newStruct));
  foundStruct = myStructList.find(structId);

您可以使用 make_pair 简化插入。您还可以避免冗余查找,因为 insert 返回一个迭代器到新插入的元素(作为一对中的第一个元素)。

  foundStruct = myStructList.insert(make_pair(structId, newStruct)).first;

最后:

return (MyStruct*) &foundStruct->second;

永远不要使用 C 风格的演员表。它可能不会达到您的预期。另外,不要在不需要时使用强制转换。&foundStruct->second 已经具有 MyStruct* 类型,那么为什么要插入强制转换呢?它唯一能做的就是隐藏一个你需要改变的地方,如果你曾经改变你的地图的值类型。

于 2013-05-08T14:30:28.377 回答
0

是的,

如果您在不知道其用途的情况下构建通用函数,则返回指针(或迭代器)可能会很危险,因为它可能变得无效。

我建议做以下两个之一:
1. 使用 std::shared_ptr 并返回它。(见下文)
2. 按值返回结构(可能更慢)

//change the difination of the list to
std::map<int, std::shared_ptr<MyStruct>>myStructList;

std::shared_ptr<MyStruct> StructManagementClass::GetStructPtr(int structId)
{
    std::map<int, std::shared_ptr<MyStruct>>::iterator foundStruct;
    foundStruct = myStructList.find(structId);
    if (foundStruct == myStructList.end())
    {
        MyStruct newStruct;
        memset(&newStruct, 0, sizeof(MyStruct));
        myStructList.structId= structId;
        myStructList.insert(pair<int, shared_ptr<MyStruct>>(structId, shared_ptr<MyStruct>(newStruct)));

       foundStruct= myStructList.find(structId);
   }

   return foundStruct->second;
于 2013-05-08T14:41:45.607 回答