2

这可能是一个简单的问题,但是,它给我带来了很多困惑。

我有一个返回填充向量的类成员:

vector<double> returnVector()
{
    return theVector;
}

我还有一个被称为toArray()接受 Iterator 的函数,以便我可以在传入的值的类型之间交替。例如:

template<typename T, typename Inverse>
T* toArray(Inverse begin, Inverse end)
{
    size_t size = distance(begin, end);
    auto pos = 0;

    T* tmp = new T[size];

    for(auto i = begin; i != end; i++)
    {
        tmp[pos] = *i;
        pos++;
    }
    return tmp;

}

在我的主要内容中,我认为可以执行以下操作;

MyClass class; 

auto* var = Functs::toArray<double>(
                std::begin(class.returnVector()),
                std::end(class.returnVector())
            );

但是,这不起作用,我似乎遇到了一些 malloc 错误。但是,我可以执行以下操作:

MyClass class;

vector<double> vals = class.returnVector(); 
auto* var = Functs::toArray<double>(
    std::begin(vals),
    std::end(vals)
);

谁能解释为什么会这样?我假设因为函数returnVector返回实际向量,因此可以访问 from beginto end?

4

2 回答 2

3

这里:

Functs::toArray<double>(
    std::begin(class.returnVector()),
    std::end(class.returnVector())
);

你的returnVector方法按值返回,所以你得到一个副本。这意味着这两个调用会产生两个不同的向量。这就是为什么您获得的范围比您预期的要大得多,以及您最终访问无效内存的原因。

如果可以,请returnVector改为返回引用。但是,如果这不是一个选项,您只需要记住始终存储对它的本地引用,就像您在其他示例中所做的那样。

另一种选择是定义便利重载:

template<typename T>
T* toArray(std::vector<T>& vec) {
    return toArray( std::begin( vec ), std::end( vec ) );
}

你可以这样称呼它:

auto* var = Functs::toArray( class.returnVector() );

我个人会选择那个选项。

于 2013-08-10T22:40:46.170 回答
2

你的代码

size_t size = distance(begin, end);

end如果不能(总是)从begin [iterator.requirements.general]访问,则具有未定义的行为。这是第一个使用toArray. 第二个例子是有效的。

如果你returnVector改成

vector<double> const& returnVector() const;

而不是toArray使用

vector<double>::data();

一般来说,最好避免返回指向已分配数据的原始指针。

于 2013-08-10T22:57:10.333 回答