Преобразовать итератор в указатель? - PullRequest
43 голосов
/ 13 апреля 2009

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

Ответы [ 12 ]

81 голосов
/ 29 января 2010

вот оно, получение ссылки на базовый указатель использования итератора:

пример:

string my_str= "hello world";

string::iterator it(my_str.begin());

char* pointer_inside_buffer=&(*it); //<--

[оператор уведомления * возвращает ссылку , поэтому при выполнении операции & на ссылке вы получите адрес].

8 голосов
/ 13 апреля 2009

Это кажется невозможным в моей ситуации, поскольку упомянутая мною функция является функцией поиска unordered_set<std::vector*>.

Используете ли вы пользовательские объекты хеш-функции / предиката? Если нет, то вы должны передать unordered_set<std::vector<int>*>::find() указатель на точный вектор, который вы хотите найти. Указатель на другой вектор с таким же содержимым не будет работать. Это не очень полезно для поиска, если не сказать больше.

Использование unordered_set<std::vector<int> > было бы лучше, потому что тогда вы могли бы выполнять поиск по значению. Я думаю, что это также потребует пользовательского объекта хеш-функции, потому что hash, насколько мне известно, не имеет специализации для vector<int>.

В любом случае, указатель на середину вектора сам по себе не является вектором, как объяснили другие. Вы не можете конвертировать итератор в указатель на вектор без копирования его содержимого.

6 голосов
/ 13 апреля 2009

Если вы можете, лучшим выбором может быть изменение функции на использование итератора для элемента или нового вектора (если он не изменяется).

Хотя вы можете делать такие вещи с массивами, поскольку знаете, как они хранятся, вероятно, плохая идея делать то же самое с векторами. &foo[1] не имеет типа vector<int>*.

Кроме того, хотя реализация STL доступна онлайн, обычно рискованно пытаться полагаться на внутреннюю структуру абстракции.

3 голосов
/ 17 апреля 2009

Вектор - это контейнер с полным владением своими элементами. Один вектор не может содержать частичное представление другого, даже const-представление. Это коренная причина здесь.

Если вам это нужно, создайте свой собственный контейнер, который имеет представления со слабым_пломером к данным, или посмотрите на диапазоны. Пара итераторов (даже указатели работают как итераторы в векторе) или, что еще лучше, boost :: iterator_range, которые работают довольно легко.

Это зависит от шаблонности вашего кода. Используйте std :: pair, если вам нужно скрыть код в cpp.

3 голосов
/ 13 апреля 2009

Ваша функция не должна принимать vector<int>*; это должно занять vector<int>::iterator или vector<int>::const_iterator в зависимости от ситуации. Затем просто введите foo.begin() + 1.

2 голосов
/ 13 апреля 2009

Прямой ответ на ваш вопрос - да. Если foo является вектором, вы можете сделать это: & foo [1].

Однако это работает только для векторов, потому что в стандарте говорится, что векторы реализуют хранилище, используя нездоровую память.

Но вы все еще можете (и, вероятно, должны) передавать итераторы вместо необработанных указателей, потому что это более выразительно. Передача итераторов не делает копию вектора.

1 голос
/ 10 июня 2011

Используйте 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());
}
1 голос
/ 13 апреля 2009

Например, мой 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].

0 голосов
/ 29 августа 2017

Безопасная версия для преобразования итератора в указатель (именно то, что это означает, независимо от последствий), и под безопасным я имею в виду не беспокоиться о необходимости разыменования итератора и вызывать возможные исключения / ошибки из-за 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);
}

напечатает что-то вроде

это = 0x0

это = 0x2202E10

Это невероятно хакерский способ сделать это, но если вам это нужно, он сделает свою работу. Вы получите некоторые предупреждения компилятора, которые, если вас действительно беспокоит, могут быть удалены с помощью #pragma

0 голосов
/ 25 сентября 2011

Vector - это шаблонный класс, и конвертировать содержимое класса в указатель небезопасно: Вы не можете наследовать векторный класс, чтобы добавить эту новую функциональность. и изменение параметра функции на самом деле является лучшей идеей. Jst создать еще один вектор int vector temp_foo (foo.begin [X], foo.end ()); и передать этот вектор вам функции

...