Преобразование из std::vector‹› в двойной указатель?

Из любопытства мне было интересно, можно ли привести std::vector‹> к двойному указателю.

У меня никогда не было проблем с передачей std::vector в качестве указателя следующим образом:

std::vector<char> myCharVector;
myCharVector.push_back('a');
myCharVector.push_back('b');
myCharVector.push_back('c');
char *myCharPointer = &myCharVector[0];

Поэтому мне было любопытно, можно ли назначить адрес указателя подобным образом:

char *myPointer = "abc";
char **myDoublePointer = &myPointer; 

Я пытался:

char **myDoublePointer = (char**)&myCharVector;

Но это не работает. Есть ли способ достичь этого?


person kbirk    schedule 03.07.2012    source источник
comment
Это что-то большее, чем любопытство?   -  person user541686    schedule 03.07.2012
comment
Какую ошибку вы получаете для этой строки: char **myDoublePointer = (char**)&myCharVector;?   -  person weidi    schedule 03.07.2012
comment
@weidi нет ошибки   -  person kbirk    schedule 03.07.2012
comment
@Pondwater Тогда что не работает, как ты сказал, не работает?   -  person weidi    schedule 03.07.2012


Ответы (3)


Вы уже знаете, что &myCharVector[0] — это указатель на char. Итак, если вы сохраните его в переменной:

char *cstr = &myCharVector[0];

то вы можете взять адрес этой переменной:

char **ptrToCstr = &cstr;

Но просто дважды разыменовать вот так:

char **ptrToCstr = &(&myCharVector[0])

недействителен, так как значение (&myCharVector[0]) еще нигде не сохранено в памяти.

person japreiss    schedule 03.07.2012
comment
Ну, это, конечно, в памяти, но это rvalue, поэтому использование его адреса запрещено в качестве меры предосторожности. - person GManNickG; 03.07.2012
comment
Не обязательно, это может быть в реестре. - person japreiss; 03.07.2012
comment
Справедливо. Чтобы пояснить мой комментарий, компилятору нетрудно выделить временное пространство стека для временного, чтобы разрешить использование его адреса. Например, учитывая char*& to_lvalue(char*&& x) { return x; }, вы можете написать char** ptrToCstr = &to_lvalue(&myCharVector[0]), но после оператора указатель будет непригоден для использования, что я и имел в виду в качестве меры предосторожности. - person GManNickG; 04.07.2012

В С++ 11 вы можете сделать:

char *myCharPointer = myCharVector.data();

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

Если цель состоит в том, чтобы иметь возможность изменить то, на что указывает указатель, то вам может понадобиться указатель на вектор, а не указатель на указатель на символ. Но STL не позволяет вам изменить базовый указатель внутри самого вектора без использования обычных векторных API (таких как resize или swap).

person jxh    schedule 03.07.2012

Вы определенно не можете этого сделать. std::vector и char ** — это совершенно разные типы объектов, и вы не можете просто «преобразовать» один объект в другой.

Причина, по которой вы смогли выполнить char *myCharPointer = &myCharVector[0], заключается в том, что myCharVector[0] дает вам char, и, таким образом, &myCharVector[0] дает вам адрес этого char, который вы можете назначить char *.

Единственный способ преобразовать полный std::vector в char * (не char **) — это зациклиться на std::vector и построить char * из данных вручную.

Например что-то вроде:

char *ptr = malloc(myCharVector.size()+1);
for (unsigned int i=0; i < myCharVector.size(); i++) {
  ptr[i] = myCharVector[i];
}
ptr[myCharVector.size()] = 0;

Тогда ptr будет строкой C из chars.

person houbysoft    schedule 03.07.2012
comment
@BenVoigt, что ты имеешь в виду? Часть о преобразовании в char *? - person houbysoft; 03.07.2012
comment
Часть о необходимости сделать копию вектора, чтобы получить непрерывный блок (чтобы индексация указателя работала), неверна. vector содержимое гарантированно хранится непрерывно, так что &v[i] == i + &v[0] - person Ben Voigt; 03.07.2012
comment
@BenVoigt: да, но это работает только до тех пор, пока вектор не изменяется, верно? - person houbysoft; 03.07.2012
comment
Вы должны быть осторожны со всем, что делает итераторы недействительными. Не все модификации подходят (замена или удаление элементов не будет проблемой. Вставка будет, если вы заранее не зарезервировали место). - person Ben Voigt; 03.07.2012