не уверен, почему объект является локальным по сравнению с ссылкой - PullRequest
0 голосов
/ 10 июля 2019

Я почти уверен, что извлекаю ссылку на Flashcard объект, который находится в области видимости, но IDE сообщает мне, что entry является локальным объектом ..

const ::std::pair<int64, Flashcard>& GetCardHandler::GetRandomFlashcard() {
  const ::std::unordered_map<int64, Flashcard>& flashcards_ = Get<FlashcardContext>()->GetFlashcardMap();
  const ::std::pair<int64, Flashcard>& entry  = *( std::next(std::begin(flashcards_), rand_between(0, flashcards_.size()) ) ); ;
  return entry;
}

Больше контекста (из FlashcardContext class) ...

const ::std::unordered_map<int64, Flashcard>& GetFlashcardMap();
...
std::unordered_map<int64, Flashcard> flashcards_ GUARDED_BY(lock_);

Flashcard s на этой карте являются постоянными из-за внутренней структуры.

1 Ответ

2 голосов
/ 10 июля 2019

value_type из std::unordered_map равно std::pair<const Key, T>. Обратите внимание на const? Это отсутствует в ваших декларациях.

В вашем случае *iterator возвращает std::pair<const int64, Flashcard>&, который вы затем сохраняете в std::pair<int64, Flashcard>&, поэтому компилятор должен создать временный std::pair объект, который является локальным для GetRandomFlashcard(), на которую вы тогда return ссылаетесь. Это то, о чем вас предупреждает компилятор.

Вам необходимо обновить декларации std::pair, чтобы они включали const:

const ::std::pair<const int64, Flashcard>& GetCardHandler::GetRandomFlashcard()
{
    const ::std::unordered_map<int64, Flashcard>& flashcards_ = Get<FlashcardContext>()->GetFlashcardMap();

    const ::std::pair<const int64, Flashcard>& entry = *( std::next(std::begin(flashcards_), rand_between(0, flashcards_.size()) ) );
    // alternatively:
    // const ::std::unordered_map<int64, Flashcard>::value_type& entry = ...;

    return entry;
}

Тем не менее, вы действительно должны использовать auto для упрощения ваших деклараций:

// pre-C++14
const ::std::pair<const int64, Flashcard>& GetCardHandler::GetRandomFlashcard()
{
    const auto &flashcards_ = Get<FlashcardContext>()->GetFlashcardMap();
    const auto &entry = *( std::next(std::begin(flashcards_), rand_between(0, flashcards_.size()) ) );
    return entry;
}
// C++14 and later
const auto & GetCardHandler::GetRandomFlashcard()
{
    const auto &flashcards_ = Get<FlashcardContext>()->GetFlashcardMap();
    const auto &entry = *( std::next(std::begin(flashcards_), rand_between(0, flashcards_.size()) ) );
    return entry;
}

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

using FlashcardMap = ::std::unordered_map<int64, Flashcard>;
using FlashcardMapEntry = FlashcardMap::value_type;

...

const FlashcardMap& GetFlashcardMap();
...
FlashcardMap flashcards_ GUARDED_BY(lock_);

...

const FlashcardMapEntry& GetCardHandler::GetRandomFlashcard()
{
    const FlashcardMap& flashcards_ = Get<FlashcardContext>()->GetFlashcardMap();
    const FlashcardMapEntry& entry = *( std::next(std::begin(flashcards_), rand_between(0, flashcards_.size()) ) );
    return entry;
}
...