我读过的lvalues是"具有已定义存储位置的内容".
而且文字和临时变量也不是左值,但没有给出这个陈述的理由.
是因为文字和临时变量没有定义存储位置?如果是的话,那么如果不在记忆中它们会在哪里居住?
我想在"定义的存储位置"中"定义"有一些意义,如果有(或没有)请告诉我.
我发布了这个答案:https://stackoverflow.com/a/28459180/2642059其中包含以下代码:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " @:" << temp << endl;
}
Run Code Online (Sandbox Code Playgroud)
是bar左值还是左值?
我问,因为我显然不能取rvalue的地址,但我可以在这里完成rvalue引用的地址.
如果你可以对左值参考执行任何操作,你可以在左值参考上区分用"&&"而不仅仅是"&"来区分两者?
在C++ 03中,Boost的Foreach使用这种有趣的技术,可以在运行时检测表达式是左值还是左值.(我发现通过这个StackOverflow问题:C++ 03中的Rvalues)
(这是一个更基本的问题,当我在思考我最近的另一个问题时出现.对此的答案可能有助于我们回答另一个问题.)
现在我已经详细说明了这个问题,在编译时在C++ 03中测试rvalue-ness,我会谈谈到目前为止我一直在尝试的事情.
我希望能够在编译时进行此检查.在C++ 11中很容易,但我对C++ 03很好奇.
我正在努力建立他们的想法,但也会对不同的方法持开放态度.他们的技术的基本思想是将此代码放入一个宏:
true ? rvalue_probe() : EXPRESSION;
Run Code Online (Sandbox Code Playgroud)
它的左侧是'true' ?,因此我们可以确定永远不会评估EXPRESSION.但有趣的是,?:运算符的行为会有所不同,具体取决于它的参数是左值还是右值(单击上面的链接获取详细信息).特别是,它将rvalue_probe以两种方式之一转换我们的对象,具体取决于EXPRESSION是否为左值:
struct rvalue_probe
{
template< class R > operator R () { throw "rvalue"; }
template< class L > operator L & () const { throw "lvalue"; }
template< class L > operator const L & () const { throw "const lvalue"; }
};
Run Code Online (Sandbox Code Playgroud)
这在运行时有效,因为可以捕获抛出的文本并用于分析EXPRESSION是左值还是右值.但我希望在编译时能够识别正在使用的转换. …
任何人都能解释rvalues,左值,POD和非POD方面的细节,下面标记的第一个表达式不正确而下面标记的第二个表达式是否正常?根据我的理解,int()和A()都应该是rvalues,不是吗?
struct A {};
int main()
{
int i;
A a;
int() = i; //Not OK (error).
A() = a; //OK.
return 0;
}
Run Code Online (Sandbox Code Playgroud) 即将推出的C++标准C++ 0x的一个很酷的新特性是"右值引用".右值引用类似于左值(正常)引用,但它可以绑定到临时值(通常,临时值只能绑定到const引用):
void FunctionWithLValueRef(int& a) {...}
void FunctionWithRValueRef(int&& a) {...}
int main() {
FunctionWithLValueRef(5); // error, 5 is a temporary
FunctionWithRValueRef(5); // okay
}
Run Code Online (Sandbox Code Playgroud)
那么,为什么他们发明了一种全新的类型,而不仅仅是删除对普通引用的限制以允许它们绑定到临时版本?
请考虑以下示例:
#include <sstream>
template <typename T>
inline std::string to_string(T const & op) {
std::ostringstream result;
result << op;
return result.str();
}
Run Code Online (Sandbox Code Playgroud)
如果我要返回结果,而不是result.str()它将自动成为右值.不是结果中包含的字符串(我假设).我的期望是它被复制并且副本作为右值返回.
所以我的问题是,合法的是:
return std::move(result.str());
Run Code Online (Sandbox Code Playgroud)
我认为它是,期望流留下一个有效的空字符串.但我不确定实际做到这一点.
当使用std::minmax结构化绑定时,我遇到了一个相当微妙的错误.似乎传递的rvalues并不总是像人们期望的那样被复制.最初我T operator[]() const在自定义容器上使用a ,但它似乎与文字整数相同.
#include <algorithm>
#include <cstdio>
#include <tuple>
int main()
{
auto [amin, amax] = std::minmax(3, 6);
printf("%d,%d\n", amin, amax); // undefined,undefined
int bmin, bmax;
std::tie(bmin, bmax) = std::minmax(3, 6);
printf("%d,%d\n", bmin, bmax); // 3,6
}
Run Code Online (Sandbox Code Playgroud)
使用GCC 8.1.1 -O1 -Wuninitialized将导致0,0打印为第一行,并且:
warning: ‘<anonymous>’ is used uninitialized in this function [-Wuninitialized]
Run Code Online (Sandbox Code Playgroud)
Clang 6.0.1 at -O2也会在没有警告的情况下给出错误的第一个结果.
在-O0GCC给出正确的结果而没有警告.对于clang,结果似乎是正确的-O1或-O0.
在rvalue仍然有效被复制的意义上,第一行和第二行不应该是等价的吗?
另外,为什么这取决于优化级别?特别是我对GCC没有发出任何警告感到惊讶.
我相信表达式T()创建了一个rvalue(由标准).但是,以下代码编译(至少在gcc4.0上):
class T {};
int main()
{
T() = T();
}
Run Code Online (Sandbox Code Playgroud)
我在技术上知道这是可能的,因为成员函数可以在temporaries上调用,而上面只是调用operator =在从第一个创建的rvalue临时T().
但从概念上讲,这就像为rvalue分配一个新值.是否允许这样做有充分的理由吗?
编辑:我发现这个奇怪的原因是它在内置类型上被严格禁止,但允许在用户定义的类型上使用.例如,int(2) = int(3)不会编译,因为这是"赋值中的无效左值".
所以我想真正的问题是,这种有点不一致的行为是否构成了语言的原因?还是出于某种历史原因?(例如,在rvalue表达式上只允许调用const成员函数在概念上会更健全,但是这可能无法完成,因为这可能会破坏一些现有代码.)
c++ language-design operator-overloading rvalue temporary-objects
在Effective C++,第3项中,Scott Meyers建议重载operator*一个名为的类Rational:
class Rational { ... };
const Rational operator*(const Rational& lhs, const Rational& rhs);
Run Code Online (Sandbox Code Playgroud)
返回值被const限定的原因在下面的行中解释:如果不是const,程序员可以编写如下代码:
(a * b) = c;
Run Code Online (Sandbox Code Playgroud)
或者,更可能是:
if (a*b = c)
Run Code Online (Sandbox Code Playgroud)
很公平.现在我很困惑,因为我认为函数的返回值,这里是operator*,是一个rvalue,因此不能赋值.我认为它不是可转让的,因为如果我有:
int foo();
foo() += 3;
Run Code Online (Sandbox Code Playgroud)
那将无法编译invalid lvalue in assignment.为什么不在这里发生?有人可以对此有所了解吗?
编辑:我在Scott Meyers的那个项目上看到过很多其他线程,但是没有人解决我在这里暴露的rvalue问题.
当在函数之间传递r值时,我想知道c ++行为.
看看这个简单的代码:
#include <string>
void foo(std::string&& str) {
// Accept a rvalue of str
}
void bar(std::string&& str) {
// foo(str); // Does not compile. Compiler says cannot bind lvalue into rvalue.
foo(std::move(str)); // It feels like a re-casting into a r-value?
}
int main(int argc, char *argv[]) {
bar(std::string("c++_rvalue"));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道当我在bar函数内部时我需要使用move函数来调用foo函数.我现在的问题是为什么?
当我在bar函数内部时,变量str应该已经是一个r值,但编译器就像是一个l值.
有人可以引用一些关于这种行为的标准吗?谢谢!