2016-03-26 5 views
0

Почему мой const ref недействителен в этом коде и как этого избежать? Я не могу копировать, это узкое место в моем приложении.Почему мой const ref недействителен?

class Foo { 
public: 
    const std::string& string() const { 
     return string; 
    } 

private: 
    std::string string = "asdf"; 
}; 

Foo foo; 
std::vector<std::pair<const std::string&, int>> invalid; 
for (int i = 0; i < 5; i++) { 
    invalid.emplace_back(std::make_pair(foo.string(), i); 
    // after this line invalid[i].first is invalid 
} 
+4

Шаблон работает таким образом, что '' make_pair' возвращает зЬй :: пару <станд :: строка, Int> 'в вызове; затем 'emplace' строит' std :: pair 'из этого. Поэтому ссылка привязана к члену временной пары, а не к 'foo.string'. Сделайте это 'invalid.emplace_back (std :: pair (foo.string(), i));' –

+0

Откуда вы знаете, что 'invalid [i] .first' недействителен? 'Foo' не присваивается конструктором перемещения. Является ли это законным для векторного элемента? (Подлинный вопрос - я еще не догнал C++ 11.) Работает ли он, если вы используете 'std :: pair ' как ваш тип элемента? –

+0

@IgorTandetnik - Сделай так, чтобы я мог его поддержать! –

ответ

1

Игорь Tandetnik уже указал на проблему в вашем коде. FWIW, я не думаю, что это хорошая идея иметь контейнеры, ссылающиеся на элементы других объектов по ссылке в любом случае - есть неявная зависимость от относительного подъема объектов. Вы можете рассмотреть возможность использования shared_ptr to const string, как в следующем примере: дедукция параметр

#include <string> 
#include <memory> 
#include <vector>                               
class Foo { 
public: 
    const std::shared_ptr<const std::string> string() const { 
     return _string; 
    } 

private: 
    std::shared_ptr<std::string> _string = std::make_shared<std::string>("asdf"); 
}; 

int main() 
{ 
    Foo foo; 
    std::vector<std::pair<std::shared_ptr<const std::string>, int>> invalid; 
    for (int i = 0; i < 5; i++) { 
     invalid.emplace_back(std::make_pair(foo.string(), i)); 
    } 
} 
1

make_pair возвращается в pair<std::string,int>, не pair<const std::string&, int>, потому что стандарт требует, чтобы это было так.

template <class T1, class T2> 
constexpr pair<V1, V2> make_pair(T1&& x, T2&& y); 

§ 20.3.3 - 8

Возвращает: pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y));

где V1 и V2 определяются следующим образом: Пусть Ui будет decay_t<Ti> для каждого Ti. Тогда каждый Vi равен X & , если Ui равно reference_wrapper, иначе Vi является Ui.

Это должно работать в соответствии со стандартом:

invalid.emplace_back(std::make_pair(std::ref(foo.string()), i)); 

и это по мне:

invalid.emplace_back(decltype(invalid)::value_type(foo.string(), i)); 
+0

Очень хорошие ссылки! –