【问题标题】:Returning a std::vector - right approach返回 std::vector - 正确的方法
【发布时间】:2013-04-12 22:41:27
【问题描述】:

我正在尝试创建一个将返回 std::vector 的类方法,但对执行此操作的最佳方法有点困惑。

我使用的方法是定义如下方法:

std::vector<double>* GetBins(void);

在方法中,分配一个新的 std::vector,我用数据填充它。我正在返回一个指向这个 ie 的指针。

std::vector<double>* Frequency::GetBins(void) {
    std::vector<double> *rtnVec = new std::vector<double>();
    for (_itMap = _mapFreq.begin(); _itMap != _mapFreq.end(); _itMap++ ) {
        rtnVec->push_back((*_itMap).first);
    }
    return rtnVec;
 }

(_itMap 是一个类定义的迭代器)。

在我的 main.cpp 中,我做了以下事情:

 std::vector<double>* myBins;
 myBins = myFreq3->GetBins();
 delete myBins;

我知道用这种方法,除非我删除 main.cpp 代码中的指针,否则我会得到一个悬空指针,所以它已经有点“危险”了。从类方法返回新的 std::vector 的最佳方法是什么?

谢谢大家 皮特

【问题讨论】:

  • 为什么要退货?创建一个BinsProcessor 接口并要求Frequency 使用您的CustomBinsProcessor 处理这些垃圾箱。

标签: c++ vector stl


【解决方案1】:

最好的方式是按值返回:

std::vector<double> Frequency::GetBins() {
    std::vector<double> rtnVec;
    rtnVec.reserve(_mapFreq.size()); // reserve enough size, no reallocations
    for (_itMap = _mapFreq.begin(); _itMap != _mapFreq.end(); ++_itMap ) {
        rtnVec.push_back(_itMap->first);
    }
    return rtnVec;
}

然后你会像这样使用函数:

std::vector<double> myBins = myFreq3->GetBins();
// no need for delete!

编译器可能会使用RVO 并且不执行任何复制。如果您使用的是 C++11,则移动语义将确保不执行任何复制。

【讨论】:

  • for (auto&amp;&amp; elem: _mapFreq) { rtnVec.push_back(elem.first); }
  • @MSalters 是的,这是迭代地图的更好方法。但是,OP 专门询问返回语义,使用基于范围的 for 循环在这里没有区别。
  • 公平点。考虑一下,我还要添加一个rtnVec.reserve(_mapFreq.size())。同样,不会直接影响返回类型,但它确实消除了您在填写 rtnVec 时会产生的一些复制。
  • @Pete855217 请注意,如果您尝试从函数外部访问向量,则在该示例中返回 const 引用将触发未定义的行为。只需按答案中所示的值返回即可。
  • @Pete855217 使用后缀增量(X++)也是完全有效的。但是,使用前缀增量 (++X) 可以避免制作迭代器的额外副本。
【解决方案2】:

按值返回

std::vector<double> Frequency::GetBins(void) {
    std::vector<double> rtnVec;

    // ...

    return rtnVec;
 }

但是如果你想通过指针返回,你可以使用智能指针:

std::unique_ptr<std::vector<double>> Frequency::GetBins(void) {
    std::unique_ptr<std::vector<double>> rtnVec(new std::vector<double>());

    //...

    return rtnVec;
 }

【讨论】:

  • 除非使用move语义,否则按值返回会导致深拷贝,远非最优。
  • @ddriver 在 OP 的设计和这篇文章中,RVO 都将隐式发生,并且复制省略应该发生在调用站点。在 C++11 中,其代码的紧密变体将继续使用 RVO,或隐式使用 move
【解决方案3】:

如果您想避免复制/悬空指针/...,另一种方法是简单地通过引用方法传递您的 std::vector

void Frequency::GetBins( std::vector<double>& bins ) {
    for (_itMap = _mapFreq.begin(); _itMap != _mapFreq.end(); _itMap++ ) {
        bins->push_back((*_itMap).first);
    }
 }

你只需要在之前定义它:

 std::vector<double> myBins;
 myFreq3->GetBins(myBins);

【讨论】:

    猜你喜欢
    • 2011-03-04
    • 2011-09-06
    • 2017-10-19
    • 2021-07-12
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多