Подтвердить что ты не робот

Преобразовать итератор в указатель?

У меня есть 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.

4b9b3361

Ответ 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