3

Found workaround how to use rvalue as lvalue :

&(std::string()=std::string("Hello World"));

but not sure is it legal to use this construction.

Code same to this is working for me

typedef std::pair<const char *, const std::string *> custom_pair;

std::ostream & operator <<(std::ostream & os, const custom_pair & kv)
{
    if (kv.first && kv.second && !kv.second->empty())
      os << kv.first << *kv.second;

    return os;
  }

std::ostringstream q;
q << custom_pair("example_string=", &(std::string() = IntToString(1)));

where custom_pair constructor needs address as second parameter, but can someone explain is it correct to use this?

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    Show what `custom_pair()` actually is please. Provide a [MCVE] as required! Keep your questions self contained, instead of reffering to links only (these may be used as additional info). – πάντα ῥεῖ Feb 02 '17 at 19:36
  • 2
    This seems like trouble. Storing the address of a temporary object? – tadman Feb 02 '17 at 19:41
  • *Code same to this is working for me* What does *working* mean in your case? I suspect you will run into UB if you dereference the pointer. – R Sahu Feb 02 '17 at 19:41
  • That's super dangerous. Store the result of `IntToString` elsewhere, or you'll have a dangling pointer. – AndyG Feb 02 '17 at 19:42
  • There are many ways to shoot your own leg in C++. You found yet another one. Why second type is pointer to string instead of just string? Premature optimization? – Slava Feb 02 '17 at 19:44
  • Code working means that it is working, not in UB, but just fine anywherre I tried it. I defenitly can store this value, but my question was right about this construction. Also there are a lot of usage of this pair, and I want to optimize refactoring – Всеволод Ившин Feb 02 '17 at 19:44
  • @ВсеволодИвшин: It's almost certainly UB, just the kind of UB that happens to work on the compilers you've used. I suspect turning warnings up to maximum would alert you of the problem (at least on some compilers). The address of a temporary is nonsensical; even if it works now, there is no guarantee it will be portable to other compilers, architectures, or even different versions of the same compiler. I will admit, [this answer](http://stackoverflow.com/a/8383019/364696) seems confident it's legal... – ShadowRanger Feb 02 '17 at 19:47
  • I don't see how this is converting an rvalue into an lvalue. It is simply taking the address of an rvalue which is undefined behavior if you use that address later. – imreal Feb 02 '17 at 19:48
  • To be clear, I'm not going to call myself an expert here. But I think the people who are might want to follow up [here](http://stackoverflow.com/a/8383019/364696) to suss out whether that answer is correct, or UB. – ShadowRanger Feb 02 '17 at 19:51
  • @ShadowRanger - The `operator=` returns an lvalue, so that "converts" the rvalue to an lvalue which allows the address to be taken. However, you have to use the address immediately, before the temporary goes away at the end of the full expression. Standing on one leg at the edge of a cliff is also legal, but I wouldn't want to try that either. – Bo Persson Feb 02 '17 at 21:49

3 Answers3

2

It's ok in your use case. The temporary object is destroyed at the semicolon after the "<<" operation. By then, it is no longer in use.

Be careful not to use this pattern when the pointer might still be used after the temporary is destroyed.

That said, I would not accept this code in a code review. Everyone reading this would have too much trouble to determine why it works. As you can see by the comments below your question.

Ludwig Schulze
  • 2,155
  • 1
  • 17
  • 36
2

but not sure is it legal to use this construction.

You are on the border of running into UB.

std::ostringstream q;
q << custom_pair("example_string=", &(std::string() = IntToString(1)));

works ok since all the temporary objects are still alive when the pointer is dereferenced. Change that to:

std::ostringstream q;
custom_pair p("example_string=", &(std::string() = IntToString(1)));
q << p;

and you are suddenly in UB territory.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

Found workaround how to use rvalue as lvalue

You do not need workaround on how to use rvalue as lvalue, but rather fix your code that you do not need this workaround. For example second type of the pair should be std::string, not const std::string * and all your problems would go away.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • Thats a good advice, but in this case we making copy of object, so thats not optimal in memory using parameter, no? – Всеволод Ившин Feb 02 '17 at 19:55
  • @ВсеволодИвшин Classic premature optimization – Ludwig Schulze Feb 02 '17 at 19:57
  • @ВсеволодИвшин "premature optimization is root of all evil". Before of all rvalue, if you would not "convert" it to lvalue would be efficiently moved into parameter. So your code would be clean, readable and still fast. – Slava Feb 02 '17 at 19:57
  • @ВсеволодИвшин: And even if the optimization really is necessary, on C++11 and higher, if both your arguments are r-values, `std::pair` should be moving them into its internal storage, which is basically just pointer copies, not copying object contents at all. You could even help it out by use `std::string` for both elements, and (if on C++14 or higher) passing the first argument as `"example_string="s` (note `s` prefix) so it's a `std::string` literal, not a C-style string literal (the `std::string` is still constructed, but it uses compile time stored length to do so, saving `strlen`). – ShadowRanger Feb 02 '17 at 20:14