libreria iterators iteradores assigning c++ stl pointers vector iterator

c++ - iterators - ¿Convertir iterador en puntero?



libreria stack c++ (12)

Tengo un std::vector con n elementos. Ahora necesito pasar un puntero a un vector que tiene los últimos n-1 elementos para una función.

Por ejemplo, mi vector<int> foo contiene (5,2,6,87,251) . Una función toma vector<int>* y quiero pasarle un puntero a (2,6,87,251) .

¿Puedo tomar (con seguridad) el iterador ++foo.begin() , convertirlo a un puntero y pasarlo a la función? O usa &foo[1] ?

ACTUALIZACIÓN: La gente sugiere que cambie mi función para tomar un iterador en lugar de un puntero. Eso no parece posible en mi situación, ya que la función que mencioné es la función find de unordered_set<std::vector*> . Entonces, en ese caso, ¿está copiando los elementos n-1 de foo en un nuevo vector y llamando a find con un puntero a esa la única opción? Muy ineficiente! Es como Shlemiel el pintor, especialmente porque tengo que consultar muchos subconjuntos: los últimos elementos n-1 , luego n-2 , etc. y ver si están en el conjunto unordered_set .


Eso no parece posible en mi situación, ya que la función que mencioné es la función find de unordered_set<std::vector*> .

¿Está utilizando objetos de función hash / predicado personalizados? De lo contrario, debe pasar unordered_set<std::vector<int>*>::find() al puntero al vector exacto que desea encontrar. Un puntero a otro vector con los mismos contenidos no funcionará. Esto no es muy útil para búsquedas, por decir lo menos.

Usar unordered_set<std::vector<int> > sería mejor, porque entonces podría realizar búsquedas por valor. Creo que también requeriría un objeto de función hash personalizado porque el hash no tiene una especialización para el vector<int> que yo sepa.

De cualquier manera, un puntero en el medio de un vector no es en sí un vector, como otros han explicado. No puede convertir un iterador en un puntero a vector sin copiar su contenido.


Por ejemplo, mi vector<int> foo contiene (5,2,6,87,251). Una función toma vector<int>* y quiero pasarle un puntero a (2,6,87,251).

Un puntero a un vector<int> no es en absoluto lo mismo que un puntero a los elementos del vector.

Para hacer esto, necesitará crear un nuevo vector<int> con solo los elementos que desea para pasar un puntero. Algo como:

vector<int> tempVector( foo.begin()+1, foo.end()); // now you can pass &tempVector to your function

Sin embargo, si su función toma un puntero a una matriz de int, entonces puede pasar &foo[1] .


La respuesta directa a su pregunta es sí. Si foo es un vector, puedes hacer esto: & foo [1].

Sin embargo, esto solo funciona para los vectores, porque el estándar dice que los vectores implementan el almacenamiento mediante el uso de memoria contigua.

Pero aún puede (y probablemente debería) pasar iteradores en lugar de punteros sin procesar porque es más expresivo. Pasar iteradores no hace una copia del vector.


No he probado esto, pero ¿podrías usar un conjunto de pares de iteradores? Cada par de iteradores representaría el iterador de inicio y final del vector de secuencia. P.ej:

typedef std::vector<int> Seq; typedef std::pair<Seq::const_iterator, Seq::const_iterator> SeqRange; bool operator< (const SeqRange& lhs, const SeqRange& rhs) { Seq::const_iterator lhsNext = lhs.first; Seq::const_iterator rhsNext = rhs.first; while (lhsNext != lhs.second && rhsNext != rhs.second) if (*lhsNext < *rhsNext) return true; else if (*lhsNext > *rhsNext) return false; return false; } typedef std::set<SeqRange, std::less<SeqRange> > SeqSet; Seq sequences; void test (const SeqSet& seqSet, const SeqRange& seq) { bool find = seqSet.find (seq) != seqSet.end (); bool find2 = seqSet.find (SeqRange (seq.first + 1, seq.second)) != seqSet.end (); }

Obviamente, los vectores deben mantenerse en otro lugar como antes. Además, si se modifica un vector de secuencia, entonces su entrada en el conjunto debería eliminarse y volverse a agregar ya que los iteradores pueden haber cambiado.

Jon


Si puede, una mejor opción puede ser cambiar la función para llevar un iterador a un elemento o un nuevo vector (si no se modifica).

Si bien puede hacer este tipo de cosas con arreglos ya que sabe cómo se almacenan, probablemente sea una mala idea hacer lo mismo con los vectores. &foo[1] no tiene el vector<int>* tipo vector<int>* .

Además, si bien la implementación de STL está disponible en línea, por lo general es riesgoso intentar confiar en la estructura interna de una abstracción.


Si su función realmente toma vector<int> * (un puntero al vector), entonces debe pasar &foo ya que será un puntero al vector. Obviamente, eso no resolverá simplemente su problema, pero no puede convertir directamente un iterador a un vector, ya que la memoria en la dirección del iterador no abordará directamente un vector válido.

Puedes construir un nuevo vector llamando al constructor vectorial :

template <class InputIterator> vector(InputIterator, InputIterator)

Esto construye un nuevo vector copiando los elementos entre los dos iteradores. Lo usarías más o menos así:

bar(std::vector<int>(foo.begin()+1, foo.end());


Su función no debe tomar vector<int>* ; debería tomar vector<int>::iterator o vector<int>::const_iterator según corresponda. Entonces, solo pasa en foo.begin() + 1 .


Un vector es un contenedor con plena propiedad de sus elementos. Un vector no puede contener una vista parcial de otro, incluso una vista const. Esa es la causa raíz aquí.

Si lo necesita, haga su propio contenedor que tenga vistas con weak_ptr''s a los datos, o mire los rangos. Un par de iteradores (incluso los punteros funcionan bien como iteradores en un vector) o, mejor aún, boost :: iterator_range que funcionan bastante bien.

Depende de la capacidad de tentación de tu código. Use std :: pair si necesita ocultar el código en una cpp.


Una versión segura para convertir un iterador en un puntero (exactamente lo que eso significa independientemente de las implicaciones) y seguro me refiero a no tener preocupaciones sobre tener que eliminar la referencia del iterador y causar posibles excepciones / errores debido a end() / otras situaciones

#include <iostream> #include <vector> #include <string.h> int main() { std::vector<int> vec; char itPtr[25]; long long itPtrDec; std::vector<int>::iterator it = vec.begin(); memset(&itPtr, 0, 25); sprintf(itPtr, "%llu", it); itPtrDec = atoll(itPtr); printf("it = 0x%X/n", itPtrDec); vec.push_back(123); it = vec.begin(); memset(&itPtr, 0, 25); sprintf(itPtr, "%llu", it); itPtrDec = atoll(itPtr); printf("it = 0x%X/n", itPtrDec); }

imprimirá algo así como

it = 0x0

it = 0x2202E10

Es una forma increíblemente hacky de hacerlo, pero si lo necesitas, hace el trabajo. Recibirás algunas advertencias del compilador que, si realmente te molestan, se pueden eliminar con #pragma


Use vector::front , debería ser la solución más portátil. Lo he usado cuando estoy interactuando con una API fija que quiere un char ptr. Ejemplo:

void funcThatTakesCharPtr(char* start, size_t size); ... void myFunc(vector<char>& myVec) { // Get a pointer to the front element of my vector: char* myDataPtr = &(myVec.front()); // Pass that pointer to my external API: funcThatTakesCharPtr(myDataPtr, myVec.size()); }


Vector es una clase de plantilla y no es seguro convertir el contenido de una clase en un puntero: No puede heredar la clase de vector para agregar esta nueva funcionalidad. y cambiar el parámetro de la función es en realidad una mejor idea. Jst crea otro vector de int vector temp_foo (foo.begin [X], foo.end ()); y pasa este vector a tus funciones


aquí está, obteniendo una referencia al puntero correspondiente de un uso de iterador:

ejemplo:

string my_str= "hello world"; string::iterator it(my_str.begin()); char* pointer_inside_buffer=&(*it); //<--

[aviso operador * devuelve una referencia, por lo que hacer & en una referencia le dará la dirección].