Преобразовать итератор в указатель?
У меня есть std::vector
с элементами n
. Теперь мне нужно передать указатель на вектор, который имеет последние элементы n-1
для функции.
Например, мой vector<int> foo
содержит (5,2,6,87,251)
. Функция принимает vector<int>*
, и я хочу передать ей указатель на (2,6,87,251)
.
Могу ли я (безопасно) взять итератор ++foo.begin()
, преобразовать его в указатель и передать его функции? Или используйте &foo[1]
?
ОБНОВЛЕНИЕ: Люди предполагают, что я меняю свою функцию на использование итератора вместо указателя. Это кажется невозможным в моей ситуации, так как функция, о которой я упомянул, является функцией find
unordered_set<std::vector*>
. Итак, в этом случае копирование элементов n-1
из foo
в новый вектор и вызов find
с указателем на это единственный вариант? Очень неэффективно! Это, как Шлемиэль, художник, тем более, что я должен запросить множество подмножеств: последние n-1
, затем n-2
и т.д. Элементы и посмотреть, находятся ли они в unordered_set
.
Ответы
Ответ 1
Это кажется невозможным в моей ситуации, так как функция, о которой я упомянул, является функцией find unordered_set<std::vector*>
.
Используете ли вы пользовательские объекты функции хеширования/предиката? Если нет, то вы должны передать unordered_set<std::vector<int>*>::find()
указатель на точный вектор, который вы хотите найти. Указатель на другой вектор с тем же содержимым не будет работать. Это не очень полезно для поисков, если не сказать больше.
Использование unordered_set<std::vector<int> >
было бы лучше, потому что тогда вы могли бы выполнять поиск по значению. Я думаю, что для этого также потребуется специальный объект функции хэш-функции, потому что hash
, насколько мне известно, не имеет специализации для vector<int>
.
В любом случае указатель на середину вектора сам по себе не является вектором, как объяснили другие. Вы не можете преобразовать итератор в указатель на вектор без копирования его содержимого.
Ответ 2
вот он, получив ссылку на соответствующий указатель использования итератора:
Пример:
string my_str= "hello world";
string::iterator it(my_str.begin());
char* pointer_inside_buffer=&(*it); //<--
[оператор уведомления возвращает ссылку , поэтому и по ссылке вы получите адрес].
Ответ 3
Если вы можете, лучшим выбором может быть изменение функции, чтобы либо итератор переместил элемент или новый вектор (если он не изменился).
Хотя вы можете делать подобные вещи с помощью массивов, так как вы знаете, как они хранятся, вероятно, плохая идея сделать то же самое с векторами. &foo[1]
не имеет типа vector<int>*
.
Кроме того, хотя реализация STL доступна в Интернете, обычно рискованно пытаться полагаться на внутреннюю структуру абстракции.
Ответ 4
Ваша функция не должна принимать vector<int>*
; он должен принимать vector<int>::iterator
или vector<int>::const_iterator
, если это необходимо. Затем просто перейдите в foo.begin() + 1
.
Ответ 5
Вектор - это контейнер с полным правом владения его элементами. Один вектор не может содержать частичный вид другого, даже const-view. Это первопричина здесь.
Если вам это нужно, создайте свой собственный контейнер, который имеет представления со значением weak_ptr для данных, или просмотрите диапазоны. Пара итераторов (даже указатели хорошо работают как итераторы в вектор) или, что еще лучше, boost:: iterator_range, которые работают довольно плавно.
Это зависит от templatability вашего кода. Используйте std:: pair, если вам нужно скрыть код в cpp.
Ответ 6
Прямой ответ на ваш вопрос - да. Если foo - вектор, вы можете сделать это: & foo [1].
Это работает только для векторов, потому что в стандарте говорится, что векторы реализуют память с использованием условной памяти.
Но вы все еще можете (и, вероятно, должны) передавать итераторы вместо необработанных указателей, потому что это более выразительно. Передача итераторов не делает копию вектора.
Ответ 7
Например, my vector<int> foo
содержит (5,2,6,87,251). Функция принимает vector<int>*
, и я хочу передать ей указатель на (2,6,87,251).
Указатель на vector<int>
не является тем же самым, что и указатель на элементы вектора.
Для этого вам нужно будет создать новый vector<int>
с помощью только тех элементов, которые вы хотите, чтобы передать указатель. Что-то вроде:
vector<int> tempVector( foo.begin()+1, foo.end());
// now you can pass &tempVector to your function
Однако, если ваша функция принимает указатель на массив int, вы можете передать &foo[1]
.
Ответ 8
Если ваша функция действительно принимает vector<int> *
(указатель на вектор), вы должны пройти &foo
, так как это будет указатель на вектор. Очевидно, что это не просто решит вашу проблему, но вы не можете напрямую преобразовать итератор в вектор, так как память по адресу итератора не будет напрямую адресовать действительный вектор.
Вы можете построить новый вектор, вызвав конструктор vector :
template <class InputIterator> vector(InputIterator, InputIterator)
Это создает новый вектор, копируя элементы между двумя итераторами. Вы бы использовали его примерно так:
bar(std::vector<int>(foo.begin()+1, foo.end());
Ответ 9
Я не тестировал это, но вместо этого вы могли бы использовать набор пар итераторов? Каждая пара итераторов будет представлять собой начальный и конечный итератор вектора последовательности. Например:.
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 ();
}
Очевидно, что векторы должны храниться в другом месте, как и раньше. Также, если вектор последовательности изменен, его запись в наборе должна быть удалена и повторно добавлена, поскольку итераторы могут быть изменены.
Джон
Ответ 10
Используйте vector::front
, это должно быть самое портативное решение. Я использовал это, когда я взаимодействую с фиксированным API, который хочет char ptr. Пример:
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());
}
Ответ 11
Вектор - это класс шаблона, и небезопасно преобразовать содержимое класса в указатель:
Вы не можете наследовать векторный класс, чтобы добавить эту новую функциональность.
и изменение параметра функции на самом деле является лучшей идеей.
Jst создать другой вектор int
vector temp_foo (foo.begin [X], foo.end());
и передать этот вектор вам функции
Ответ 12
Безопасная версия для преобразования итератора в указатель (именно это означает независимо от последствий) и безопасным я имею в виду не беспокойство о необходимости разыменовать итератор и вызывать возможные исключения/ошибки из-за end()
/других ситуаций
#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);
}
напечатает что-то вроде
it = 0x0
it = 0x2202E10
Это невероятно хакерский способ сделать это, но если вам это нужно, он выполняет эту работу. Вы получите предупреждения о компиляторе, которые, если вас действительно беспокоят, можно удалить с помощью #pragma