#include <vector>
#include <cstdio>
using namespace std;
int f()
{
int* a = new int(3);
return *a;
}
int main()
{
//printf("%p\n", &f());
vector<int> v{3};
printf("%p\n", &(*(v.begin())));
}
Я не могу взять адрес f(). Если я прокомментирую "printf("%p\n", &f());
*(v.begin())
есть int&
. f()
есть int
.
@wohlstad, но *a также выделяется в куче с действительным адресом
f
не возвращает объект, выделенный в куче (который фактически просочился). Он возвращает временную копию значения int
.
Итак, как оператор * std::vector может напрямую возвращать первый элемент? @вольстад
@DevSolar Эрр, нет. Попробуйте: std::is_same<decltype(*v.begin()), int>::value.
@KonradRudolph Я имел в виду комментарий ОП (один комментарий выше моего), в котором упоминалось, что то, что возвращает f, - «*a также выделяется в куче» (что неверно).
@KonradRudolph Я исправлен. В стандарте написано "конвертируемый в Т", и я почему-то мысленно отбросил "конвертируемый в". Ошибка CppReference.com также не помогла. ;-)
Функция f возвращает временный объект типа int
int f()
{
int* a = new int(3);
return *a;
}
Вы не можете применять адрес оператора для временного объекта.
Вы можете вернуть ссылку на созданный динамически объект, например,
int & f()
{
int* a = new int(3);
return *a;
}
И в этом случае этот вызов printf написан как
printf("%p\n", ( void * )&f());
Будет правильно.
Таким образом, правильный ответ должен быть: * оператор вектора возврата по ссылке. Спасибо!
@xiutao Нет. Пожалуйста.:)
@DevSolar В моем ответе ясно написано, что «оператор разыменования действительно возвращает ссылку на указанный объект итератором». Так что ваш комментарий не имеет смысла. Что касается функции f, то она возвращает ссылку, полученную путем разыменования указателя на динамически размещенный объект в операторе return. Это полная аналогия с разыменованием итератора, возвращаемого функцией begin.
@DevSolar Да, вы правы, v.begin() возвращает vector::iterator. Но это не то, что я хотел знать. Что я вынес из этого ответа, так это то, что оператор разыменования возвращает ссылку.
Я не могу взять адрес f(), если я прокомментирую "printf("%p\n", &f());
как можно взять адрес *(v.begin())?
С другой стороны, std::vector::begin возвращает итератор к первому элементу вектора (в случае, если вектор не пуст). Затем применение * к v.begin() дает нам тот самый первый элемент (т.е. *(v.begin()) является lvalue), адрес которого мы можем взять.
С другой стороны, f сама возвращает значение — это просто временный объект, у которого нет действительного адреса (по крайней мере, потенциально — значение может быть возвращено, согласно соглашению о вызовах, в стеке, тогда у него есть адрес , а так же в регистре ЦП, то адреса просто нет). Это значение сначала нужно присвоить переменной, чтобы вы действительно могли взять адрес.
*(v.begin())
является первым элементомint
в векторе и имеет правильный адрес.