2014-08-28 8 views
2

Вот мой код:Как вернуть ссылку на unique_ptr, содержащим nullptr

typedef map<string, unique_ptr<MyClass> > DB; 

const unique_ptr<MyClass>>& find_it(const string &key, const DB &db) 
{ 
    auto itr = db.find(key); 
    if (itr == db.end()) { 
    return nullptr; 
    } 
    return itr->second; 
} 

, возвращающие заявление вызывает предупреждение компилятора: returning reference to local temporary object [-Wreturn-stack-address].

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

1. Do not expose the map to the callers of find_it (I use typedef here is just for asking this question, in real code it is wrapped inside an interface). 
2. Using an iterator kind of thing to indicate the position of the searched item is a hassle to me, I like to avoid it. 

учитывая это, лучшее, что я могу придумать это сломать find_it() 2 фу nctions:

bool exists(const string &key, const DB &db) 
{ 
    auto itr = db.find(key); 
    return itr != db.end(); 
} 

const unique_ptr<MyClass>>& find_it(const string &key, const DB &db) 
{ 
    auto itr = db.find(key); 
    assert(itr != db.end()); 
    return itr->second; 
} 

Любые предложения?

+4

Вы не можете вернуть ссылку на 'nullptr' так же, как вы не можете вернуть ссылку' int & 'на' 0'. Кроме того, я не понимаю, как возвращать итераторы - это хлопот - вам все равно придется разыгрывать указатель. Вместо этого вы должны использовать 'boost :: optional ' (или использовать другой 'необязательный' класс, возможно, один написанный вами самим), если пользователю не нужно заботиться о' unique_ptr' (и 99% случаев, он не должен - это деталь реализации). – milleniumbug

+2

возвращение ссылки на 'unique_ptr' можно считать вводящим в заблуждение. Я думаю, что возвращение необработанного указателя или «shared_ptr» было бы лучше. но возврат объекта итератора будет лучше, чем оба. –

+0

Почему бы просто не взять параметры в качестве итераторов, вернуть итератор в положение успеха и 'db.end()' при ошибке? – 0x499602D2

ответ

6

Оператор return nullptr неявно создает экземпляр unique_ptr<MyClass>, и вы затем возвращаете ссылку на него, следовательно, предупреждение. Простое решение состоит в том, чтобы определить staticunique_ptr<MyClass>, который содержит nullptr и вместо этого возвращает ссылку на это.

const unique_ptr<MyClass>& find_it(const string &key, const DB &db) 
{ 
    static unique_ptr<MyClass> not_found; 

    auto itr = db.find(key); 
    if (itr == db.end()) { 
    return not_found; 
    } 
    return itr->second; 
} 

Лучшим решением может быть использование boost::optional. Измените тип возврата на boost::optional<std::unique_ptr<MyClass>> const&, а затем верните boost::none, если объект не найден.

+0

Итак, мы должны инициализировать not_found до nullptr, верно? –

+0

@my_question [default constructor] (http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr) сделает это за вас. Вы можете построить его с аргументом 'nullptr', если хотите более четко узнать, что вы делаете. – Praetorian