Шаблоны выражений, которые сохраняются по ссылке, обычно делают это для повышения производительности, но с оговоркой они могут использоваться только как временные
Взятые из документации Boost.Proto (которая может бытьиспользуется для создания шаблонов выражений):
Примечание Проницательный читатель заметит, что объект y, определенный выше, останется с висячей ссылкой на временное int.В разновидностях высокопроизводительных приложений, использующих Proto-адреса, обычно строят и оценивают дерево выражений до того, как какие-либо временные объекты выходят из области видимости, поэтому часто возникает такая висячая ссылочная ситуация, но об этом, безусловно, нужно знать.,Proto предоставляет утилиты для глубокого копирования деревьев выражений, чтобы их можно было передавать как типы значений, не заботясь о висячих ссылках.
В исходном примере это означает, что вы должны сделать:
std::cout << C(std::string("hello2")).s << std::endl;
Таким образом, временное C
никогда не переживает временное std::string
.В качестве альтернативы вы можете сделать s
не ссылочным членом, как указали другие.
Поскольку вы упомянули C ++ 11, в будущем я ожидаю, что деревья выражений будут храниться по значению, используя семантику перемещения, чтобы избежать дорогостоящего копирования иобертки, такие как std :: reference_wrapper, по-прежнему дают возможность хранения по ссылке.Это будет хорошо работать с auto
.
Возможной версией C ++ 11 вашего кода:
class C
{
public:
explicit
C(std::string const& s_): s { s_ } {}
explicit
C(std::string&& s_): s { std::move(s_) } {}
std::string const&
get() const& // notice lvalue *this
{ return s; }
std::string
get() && // notice rvalue *this
{ return std::move(s); }
private:
std::string s; // not const to enable moving
};
Это будет означать, что код, подобный C("hello").get()
, выделит память только один раз,но все равно хорошо играть с
std::string clvalue("hello");
auto c = C(clvalue);
std::cout << c.get() << '\n'; // no problem here