Rvalue作为lvalue使用

3

发现一种解决方案,可以将rvalue用作lvalue:

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

但不确定使用这种结构是否合法。

类似于这样的代码对我有效。

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)));

custom_pair 构造函数中,需要将地址作为第二个参数传入,但是有人能解释一下使用 this 是否正确吗?


1
请展示一下 custom_pair() 到底是什么。如果需要,请提供一个 [MCVE]!请尽量自我包含问题,不要只提供链接(这些链接可以作为附加信息)。 - πάντα ῥεῖ
2
这似乎有些麻烦。存储临时对象的地址? - tadman
代码和这个一样对我来说是可以工作的。在你的情况下,“工作”是什么意思?我怀疑如果你解引用指针,会遇到未定义行为。 - R Sahu
这非常危险。将IntToString的结果存储在其他地方,否则您将拥有一个悬空指针。 - AndyG
@ShadowRanger - operator= 返回一个左值,这样“转换”了右值为左值,从而允许取地址。但是,在完整表达式的末尾临时对象消失之前,必须立即使用该地址。在悬崖边上单脚站立也是合法的,但我也不想尝试。 - Bo Persson
显示剩余5条评论
3个回答

2

在您的使用情况下,这是可以的。临时对象会在“<<”操作符后的分号处被销毁。此时,它不再使用。

当指针在临时对象被销毁后可能仍然被使用时,请勿使用此模式。

话虽如此,我在代码审查中不会接受这段代码。每个读者都会对它的工作原理感到困惑,正如您在问题下面看到的评论一样。


是的,我明白,这看起来像胡说八道,但它的工作方式激励我回答这个问题。 - Всеволод Ившин

2

但不确定使用这种结构是否合法。

您正在接近UB的边界。

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

在指针解除引用时,所有临时对象仍然存活,因此运作良好。将其更改为:

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

你突然进入了UB领域。

0
发现了如何使用rvalue作为lvalue的解决方法。
您不需要解决如何使用rvalue作为lvalue的问题,而是修复您的代码,使您不需要这个解决方法。例如,pair的第二种类型应该是std::string,而不是const std::string *,这样所有的问题都会消失。

这是一个很好的建议,但在这种情况下,我们正在复制对象,因此使用参数在内存中不是最优的选择,对吧? - Всеволод Ившин
经典的过早优化。 - Ludwig Schulze
“过早地优化是万恶之源”。在所有的rvalue之前,如果你不将其“转换”为lvalue,那么它将被有效地移入参数。因此你的代码会更加干净、易读且依然快速。 - Slava
@ВсеволодИвшин:即使优化确实是必要的,在C++11及更高版本中,如果您的两个参数都是r-values,则std::pair应该将它们移动到其内部存储中,这基本上只是指针复制,根本不会复制对象内容。您甚至可以通过使用std::string作为两个元素,并(如果在C++14或更高版本上)将第一个参数传递为"example_string="s(注意s前缀),以便它成为std::string字面量,而不是C风格的字符串字面量(std::string仍然被构造,但它使用编译时存储的长度来完成,从而节省了strlen)。 - ShadowRanger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接