C++ 何时返回向量迭代器而不是向量?

C++ 何时返回向量迭代器而不是向量?,c++,vector,iterator,C++,Vector,Iterator,假设我们有一个函数1: vector<T>::iterator GetSomething() { vector<T> vec; // Update vec with something... return vec.begin(); } 向量::迭代器GetSomething() { 向量向量机; //用一些东西更新vec。。。 返回vec.begin(); } 和另一个功能2: vector<T> GetSomething() { vector

假设我们有一个函数1:

vector<T>::iterator GetSomething()
{
 vector<T> vec;

 // Update vec with something...

 return vec.begin();
}
向量::迭代器GetSomething() { 向量向量机; //用一些东西更新vec。。。 返回vec.begin(); } 和另一个功能2:

vector<T> GetSomething()
{
 vector<T> vec;

 // Update vec with something...

 return vec;
}
向量GetSomething() { 向量向量机; //用一些东西更新vec。。。 返回向量; } 在什么情况下,我们更喜欢功能1? 还有,向量对象的寿命是多少?
我们如何知道迭代器是否指向空向量?可能需要传递一对迭代器来确定开始/结束。

您不应该将迭代器返回到本地分配的向量。这是一种未定义的行为

解释很简单:
vectorvec将在您离开函数后销毁


第二个选项更好,最有可能的是返回值优化,它将准确地在应该返回的位置构造向量。

向量的生存期,就像所有其他自动变量一样,以声明它的块的范围结束

因此,如果您返回迭代器,它将指向释放的内存,并执行各种有趣的操作,如使程序崩溃


如果返回向量本身,它将与其所有内容一起复制,但原始向量仍会在块的末尾“消失”。

向量迭代器仅对其来源的向量有效,因此将迭代器返回到局部向量是没有用的

仅当将向量所属的向量作为参数引用传递时,才返回向量迭代器:

std::vector<int>::iterator find(std::vector<int>& v, int i)
{
    // do findie stuff
    return std::find(std::begin(v), std::end(v), i);
}
std::vector::迭代器查找(std::vector&v,inti)
{
//做芬迪的事
返回std::find(std::begin(v),std::end(v),i);
}
您永远不会希望这样做:

vector<T>::iterator GetSomething()
{
    vector<T> vec;

    // Update vec with something...

    return vec.begin(); // this iterator will be bad when it arrives
}
向量::迭代器GetSomething() { 向量向量机; //用一些东西更新vec。。。 return vec.begin();//此迭代器到达时将失效 }

一旦向量在函数末尾被销毁,它的迭代器将失效。

除了关于返回指向堆栈上消失的对象的指针的一般注释外,选项1要求提供一对方法(函数取消资格选项1):开始和结束。C++中的迭代器不工作,如java、python和许多其他。当函数返回时,vector
vec
不再存在。该向量提供的任何迭代器对于调用方都将无效。这些迭代器的大多数用法(特别是去引用)都会导致调用方表现出未定义的行为

函数返回迭代器的唯一时间是在函数返回后保证提供迭代器的向量存在的情况下。实际上,只有三种情况下可以这样做。第一个是如果向量作为参数传递给函数,例如

 std::vector<int>::iterator func(std::vector<int> &vec)
 {
     return vec.begin();
 }
std::vector::iterator func(std::vector&vec)
{
返回vec.begin();
}
由于调用者传递向量,因此当函数返回时,向量将存在

 std::vector<int>::iterator func(std::vector<int> &vec)
 {
     static std::vector<int> vec;
     return vec.begin();
 }
第二种情况是向量是静态的,或者在函数返回时继续存在

 std::vector<int>::iterator func(std::vector<int> &vec)
 {
     static std::vector<int> vec;
     return vec.begin();
 }
std::vector::iterator func(std::vector&vec)
{
静态std::向量向量向量;
返回vec.begin();
}
当然,使用这样的函数会带来与静态相关的所有复杂问题(例如,重入问题、需要跨线程同步使用等)

可以返回迭代器的第三种情况是将迭代器传递给函数。比如

 std::vector<int>::iterator func(std::vector<int>::iterator it)
 {
     return it + 1;
 }
std::vector::iterator func(std::vector::iterator it)
{
返回+1;
}
在这种情况下,由调用者传递一个有效的迭代器(例如,从它控制的容器中获得的迭代器),该迭代器可以递增(或递增1)


此外,如果函数返回迭代器,调用方可能需要在使用它之前检查迭代器是否有效。如果是的话,应该记录下来。例如,如果函数可能返回一个结束迭代器,则调用方应该在尝试取消引用它之前进行检查,而不是在取消引用之后进行检查。

我们从不喜欢本文中的选项1,因为迭代器无效。关联的向量已超出范围。函数1将迭代器返回到不存在的对象,因此无法正确使用。相比之下,这使函数2看起来几乎不错。@KerrekSB-为什么几乎?NRVO和move语义本身就很好。你是否过度简化了,这些实际上是类的成员,向量也是类的成员?在这种情况下,问题会变得更加有趣。@cruskal有时最好发布一个新问题,因为您的更新会使某些答案无效。答案不错,但可能是第一个/正确的示例,因此,它与问题相匹配。@J.H.Bonarius我的偏好是保持示例的简单性,因为有些读者可能没有在自己的代码中使用模板。虽然最初的问题使用了
T
,但它实际上并不是作为模板函数表示的。如果向量是成员变量呢?这是另一种情况,但您的示例是独立函数,而不是成员函数。对于一个类来说,直接或间接地向私有成员提供访问权并不是一个好主意。将迭代器返回给作为成员的向量就像返回指向成员的引用或指针一样,实际上,它允许类外的代码更改私有数据,而不受类的任何控制。我想问这个问题,不知怎么地,用一个局部向量发布了这个问题。我们可以返回常量迭代器