【问题标题】:Should my function return a pointer to std::vector, or a reference to std::vector?我的函数应该返回指向 std::vector 的指针还是对 std::vector 的引用?
【发布时间】:2013-03-20 19:53:45
【问题描述】:

我有一个std::map<int, std::vector<SomeStruct>>
并提供类似std::vector<SomeStruct> FindData(int key) 的查询。

为防止复制整个数据,我将其修改为std::vector<SomeStruct>& FindData(int key)
但是,某些key不会有数据,所以有时我没有什么可以返回。
在这种情况下,我声明一个空的std::vector<SomeStruct> 文件范围变量并返回它。

但如果我选择指向向量的指针,即std::vector<SomeStruct>* FindData(int key),那么我可以只返回NULL 来表示不存在的key

哪个更好?
我了解到在问题 (Is there other syntax for this pointer operation?) 中指向 std::vector 的指针不好(或奇怪?不确定)
而且我个人也喜欢引用std::vector,这样我可以更轻松地使用operator[],但缺点是我必须为它声明一个额外的空变量。

代码示例如下:在SomeClass.h

typedef std::vector<SomeStruct> DataVec;
typedef std::map<int, DataVec> DataMap;
DataMap m_DataMap;

现在在SomeClass.cpp:

案例一:

namespace
{
    DataVec EmptyVector;
}

DataVec& FindDatas(int key)
{
    DataMap::iterator It = m_DataMap.find(key);

    if (It == m_DataMap.end()) return EmptyVec;

    return It->second;
}

案例 2:

DataVec* FindDatas(int key)
{
    DataMap::iterator It = m_DataMap.find(key);

    if (It == m_DataMap.end()) return NULL;

    return &(It->second);
}

参考:
优点:看起来很正常 std::vector.
缺点:声明了额外的变量。

指针:
优点:查询功能更短,不需要其他变量。
缺点:看起来怪怪的(?!),你不能用p[i],你必须(*p)[i],这很烦人。

哪个更好?

【问题讨论】:

  • 返回参考;默认构造的向量是一个轻量级对象,因此周围有额外的EmptyVector 不应该引起任何关注。如果你返回nullptr,所有客户端代码都必须包含一个检查,我个人觉得这比检查空向量更烦人。
  • @Praetorian:我也有类似的想法,所以我更喜欢参考。但是客户端也必须检查if (p.empty()) return,所以可能仍然存在类似空检查的语句:(

标签: c++ stl stdvector


【解决方案1】:

这取决于您的设计要求。如果使用没有对应元素的索引调用此函数是一个编程错误,那么代码应该中止。如果是用户错误,它应该抛出异常。如果它是预期用途的一部分,那么您有三种选择,同样取决于您的设计。您可以标记问题,通常是通过返回空指针或从获取结果引用的函数返回布尔值。您可以像std::set 那样悄悄地返回一个新创建的有效对象。你可以返回一个不属于你的容器的哨兵对象,用户在使用返回值之前必须检查他们是否得到了这个对象。

【讨论】:

    【解决方案2】:

    你也可以将输出的引用作为参数,这样你就可以添加一些枚举器或布尔结果作为方法输出:

        namespace
        {
            DataVec EmptyVector;
        }
    
        bool FindDatas(int key, DataVec& output)
        {
            DataMap::iterator It = m_DataMap.find(key);
    
            if (It == m_DataMap.end()) return false;
    
            output = It->second;
                        return true;
        }
    

    【讨论】:

      【解决方案3】:

      如果您不介意为未找到的键创建新条目,则可以使用以下代码:

      DataVec& FindDatas(int key)
      {
          return m_DataMap[key];
      }
      

      一种避免未找到键的新条目的替代方法:

      DataVec& FindDatas(int key)
      {
          DataMap::iterator It = m_DataMap.find(key);    
          if (It == m_DataMap.end()) {
              // created on first unfound key and stays
              // alive until the end of the program
              static DataVec fEmpty; 
              return fEmpty; 
          }    
          return It->second;
      }
      

      【讨论】:

      • 嗨:我不想在不存在的密钥上引入额外的条目,谢谢!
      • @MarsonMao 好的,我发布了一个替代解决方案。
      • 考虑FindDatas(non_existing_key).push_back(blah)。 (不过原代码中也存在同样的问题)
      • @StackedCrooked:我有这个想法,但我不想将static 变量放入函数中,因为我有很多这样的查询函数,它会放入很多statics周围,​​这不是预期的结果。谢谢!
      • @R.MartinhoFernandes:是的,我也注意到了,我将使用const 返回值,但通常我不会在您的示例中使用push_back 之类的东西。
      猜你喜欢
      • 1970-01-01
      • 2021-02-17
      • 2016-02-19
      • 1970-01-01
      • 2011-03-18
      • 2015-11-05
      • 2017-11-13
      • 2016-03-15
      • 2016-02-12
      相关资源
      最近更新 更多