返回一个std::vector的正确方法

8
我将尝试创建一个类方法,该方法将返回std :: vector,并且有点困惑如何做到最好。
我使用的方法是定义以下方法:
std::vector<double>* GetBins(void);

在这个方法中,我会分配一个新的std::vector,并将其填充数据。然后我会返回指向这个vector的指针。

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的最佳方法?

谢谢大家 Pete


为什么需要返回任何东西?创建一个 BinsProcessor 接口,并要求 Frequency 使用您的 CustomBinsProcessor 处理箱子。 - Peter Wood
3个回答

15

最好的方法是通过值返回:

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,则移动语义将确保不进行复制。

1
或者 for (auto&& elem: _mapFreq) { rtnVec.push_back(elem.first); } - MSalters
1
@MSalters 是的,这是更好地迭代映射的方法。然而,OP特别询问了返回语义,在这里使用基于范围的for循环没有任何区别。 - mfontanini
另一个选项是返回const引用(const std::vector<double>&),如果他只想提供访问而不创建向量。 - BЈовић
2
@Pete855217 注意,在该示例中返回一个const引用,如果你试图从函数外部访问向量,将会触发未定义的行为。只需按照答案所示返回值即可。 - mfontanini
1
@Pete855217,使用后缀递增(X++)也是完全有效的。然而,使用前缀递增(++X)可以避免创建迭代器的额外副本。 - mfontanini
显示剩余5条评论

4

按值返回

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;
 }

除非使用移动语义,否则按值返回将导致深拷贝,这远非最佳选择。 - dtech
3
在原帖和这篇文章中,都会隐式出现 RVO,并且在调用处应该进行复制省略。在C++11中,与他们代码相似的变体将继续使用 RVO,或者将隐式移动。 - Yakk - Adam Nevraumont

4

如果你想避免拷贝/悬空指针等问题,另一种方法就是将你的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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接