Если у меня есть std::optional
, обернутый (скажем) вокруг
std::vector::const_iterator
, безопасно ли получить доступ к указанному
элемент с двумя последовательными операторами разыменования (*
)?
Например:
typedef std::vector<int> IVec;
// Get a valid iterator.
IVec::const_iterator it = ivec.cbegin();
assert(it != ivec.end());
// Wrap it in an optional.
std::optional<IVec::const_iterator> itOpt(it);
assert(itOpt);
// Access the iterator via double dereference.
return **itOpt;
Насколько я могу судить, это нормально, если ivec
не местный, а
Кланг жалуется:
предупреждение: возвращена ссылка на память стека, связанная с локальной переменной «itOpt» [-Wreturn-stack-address]
Полный пример:
// test.cc
// Clang complains when accessing an optional iterator.
#include <cassert> // assert
#include <iostream> // std::cout
#include <optional> // std::optional
#include <vector> // std::vector
typedef std::vector<int> IVec;
IVec ivec;
int const &getVecElementRef()
{
// Get a valid iterator.
IVec::const_iterator it = ivec.cbegin();
assert(it != ivec.end());
// Wrap it in an optional.
std::optional<IVec::const_iterator> itOpt(it);
assert(itOpt);
#if 1
// Access the iterator via double dereference.
//
// Clang complains: warning: reference to stack memory associated with
// local variable 'itOpt' returned [-Wreturn-stack-address]
return **itOpt;
#else
// This works fine (with or without the `const &` part).
auto const &tmp = *itOpt;
return *tmp;
#endif
}
int main()
{
ivec.push_back(0);
// Get an element reference using operator[].
int const &v0 = ivec[0];
std::cout << "&v0: " << &v0 << "\n";
// Get an element reference using the function. The resulting address
// is the same.
int const &v1 = getVecElementRef();
std::cout << "&v1: " << &v1 << "\n";
// Returns 0.
return v1;
}
// EOF
С Clang (v16, v18 и новейшей версии) я получаю:
$ clang++ -o test.exe -std=c++17 -g -Wall test.cc
test.cc:27:12: warning: reference to stack memory associated with local variable 'itOpt' returned [-Wreturn-stack-address]
return **itOpt;
^~~~~
1 warning generated.
$ ./test.exe
&v0: 0x5633e9c95eb0
&v1: 0x5633e9c95eb0
GCC и MSVC принимают этот пример без жалоб. (https://godbolt.org/z/f49P4s4fd).
Есть ли здесь скрытая опасность, или Кланг ошибается?
Поскольку все согласны с тем, что это ложное срабатывание, я зарегистрировал Clang Проблема № 96403.
Мне код кажется нормальным. Предупреждение похоже на ложное срабатывание.
@PepijnKramer Я пытаюсь получить доступ к элементу контейнера, используя необязательный итератор.
GCC доволен кодом еще в версии Ver. С 7,5 по 14,1.
Это ложное срабатывание. Код в порядке.
Элемент, на который ссылается возвращаемая ссылка, находится в ivec
, который является глобальным, так что это не проблема.
Здесь следует быть осторожным: возвращаемая ссылка может стать недействительной при некоторых операциях с вектором, например push
и т. д. См. Правила недействительности итератора для контейнеров C++
Тот факт, что компилятор что-то принимает, не означает, что это правильно. Что ты пытаешься сделать?