在C++中返回指向向量元素的指针

73
我在全局作用域中有一个名为myObjects的向量。 我有一个方法,使用std::vector<myObject> ::const_iterator来遍历该向量,并做一些比较以找到特定元素。 一旦我找到所需的元素,我想能够返回指向它的指针(该向量存在于全局作用域中)。
如果我返回&iterator,那么我是返回迭代器的地址还是迭代器所指向的地址?
我是否需要将const_iterator强制转换回myObject,然后返回其地址?

2
我建议您阅读Scott Meyers关于迭代器用法的文章:http://www.ddj.com/cpp/184401406 他提供了有关将const_iterator转换为iterator等方面的指导。 - Luc Touraille
9个回答

110

返回迭代器指向的对象的地址:

&(*iterator)

编辑:为了消除一些混淆:

vector <int> vec;          // a global vector of ints

void f() {
   vec.push_back( 1 );    // add to the global vector
   vector <int>::iterator it = vec.begin();
   * it = 2;              // change what was 1 to 2
   int * p = &(*it);      // get pointer to first element
   * p = 3;               // change what was 2 to 3
}

不需要指针向量或动态分配。


108
我认为将指向存储在向量中对象的指针返回不是一个好主意。如果我们在获取指针后进行 push_back() ,那会发生什么呢?向量可能会重新分配内存,导致指针失效,是吗? - Naveen
3
对于迭代器也是完全相同的。 - anon
3
是的,这就是为什么我认为最安全的方法是退还副本。 - Naveen
7
复制可能很昂贵,而且(虽然在这种情况下可能不是)如果您想修改向量中的对象会怎样? - anon
18
为了寻找与自己问题完全相同的答案,我偶然发现了这个帖子,并认为任何有相同问题的人都应该知道:重新分配 vector 将会使所有引用、指针和迭代器无效。在 vector 中插入/删除元素将会使受影响索引后面的所有指针、引用和迭代器无效。参考来源:http://www.sgi.com/tech/stl/Vector.html,https://dev59.com/5XA75IYBdhLWcg3wYH3I。在这种情况下,List 容器可能是一种替代方案。 - quaylar
显示剩余10条评论

15

返回迭代器将返回迭代器的地址。如果你想返回引用元素的方式,则应该返回迭代器本身。

请注意,为了返回迭代器/指针,您不需要将向量设为全局变量,但是向量中的操作可能会使迭代器失效。例如,向向量添加元素可能会在新的size()大于保留内存时将向量元素移动到不同的位置。从向量中给定元素前删除元素将使迭代器引用不同的元素。

在这两种情况下,取决于STL实现,仅凭偶尔发生的随机错误很难进行调试。

'是的,我不想返回迭代器,因为a)它是const的,b)它肯定只是一个本地的、临时的迭代器吧?– Krakkos'--评论后编辑

迭代器不比任何其他变量更本地或更临时,它们是可复制的。您可以返回迭代器,编译器会为您进行复制,就像使用指针一样。

现在考虑const。如果调用者想通过返回的元素(无论是指针还是迭代器)进行修改,则应使用非const迭代器。(只需从迭代器定义中删除'const_'即可)。


是的,我不想返回迭代器,因为它是常量,并且它只是一个局部的、临时的迭代器,肯定吧? - Krakkos

8
您可以使用向量的 data 函数:

返回指向向量中第一个元素的指针。

如果不想使用指向第一个元素的指针,而是使用索引,则可以尝试以下方法,例如:
//the index to the element that you want to receive its pointer:
int i = n; //(n is whatever integer you want)

std::vector<myObject> vec;
myObject* ptr_to_first = vec.data();

//or

std::vector<myObject>* vec;
myObject* ptr_to_first = vec->data();

//then

myObject element = ptr_to_first[i]; //element at index i
myObject* ptr_to_element = &element;

3
只要您的向量保持在全局范围内,您可以返回以下内容:
&(*iterator)

我要提醒你,这样做一般来说是相当危险的。如果你的向量(vector)被移出了全局范围并且被销毁,任何指向myObject的指针都会变为无效。如果你正在编写这些函数作为一个更大项目的一部分,返回非const指针可能会导致某人删除返回值。这将对应用程序产生未定义的灾难性影响。

我会重写成:

myObject myFunction(const vector<myObject>& objects)
{
    // find the object in question and return a copy
    return *iterator;
}

如果您需要修改返回的myObject,请将您的值存储为指针并在堆上分配:

myObject* myFunction(const vector<myObject*>& objects)
{
    return *iterator;
}

您可以通过这种方式控制它们何时被销毁。

像这样的东西会破坏您的应用程序:

g_vector<tmpClass> myVector;

    tmpClass t;
    t.i = 30;
    myVector.push_back(t);

    // my function returns a pointer to a value in myVector
    std::auto_ptr<tmpClass> t2(myFunction());

在指向存储在全局变量中的对象的指针中使用auto_ptr就像是给自己的脚开枪。我同意返回指向生命周期可能会更改的对象的指针是很危险的,但是你的示例也不太现实。 - Ismael

3

返回迭代器并不是一个好主意。当对向量进行修改(反转\删除)时,迭代器会变得无效。此外,迭代器是在堆栈上创建的本地对象,因此返回同一对象的地址根本不安全。我建议你使用myObject而不是向量迭代器。

编辑: 如果对象很轻,则最好返回对象本身。否则,返回存储在向量中的myObject指针。


0

我不确定是否需要返回迭代器指向的对象的地址。你只需要指针本身就可以了。你会看到STL的迭代器类自己实现了使用_Ptr来达到这个目的。所以,只需这样做:

return iterator._Ptr;

0

假设你有以下代码:

std::vector<myObject>::const_iterator first = vObj.begin();

那么向量中的第一个对象是:*first。要获取地址,请使用:&(*first)

然而,为了符合STL设计,如果您计划稍后将其传递给STL算法,则建议返回迭代器。


我想返回指向向量中myObject的指针...由于如何找到该指针的实现可能会改变,因此我不想返回迭代器。 - Krakkos

0

参考dirkgently和anon的答案,您可以调用front函数而不是begin函数,这样您就不必写*,只需写&

代码示例:

vector<myObject> vec; //You have a vector of your objects
myObject first = vec.front(); //returns reference, not iterator, to the first object in the vector so you had only to write the data type in the generic of your vector, i.e. myObject, and not all the iterator stuff and the vector again and :: of course
myObject* pointer_to_first_object = &first; //* between & and first is not there anymore, first is already the first object, not iterator to it.

0

你正在向量中存储myObject的副本。因此,我认为复制myObject实例不是一项昂贵的操作。那么,我认为最安全的方法是从您的函数返回myObject的副本。


我需要更改返回的myObject的一些属性,因此不想制作副本...通过使用指针方法,我可以直接编辑它们。 - Krakkos

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