让
int a = 0;
Run Code Online (Sandbox Code Playgroud)
那么是标准C++中(int)a的右值?
不同的编译器显示此代码的不同结果:
#include <iostream>
using namespace std;
void f(int& x)
{
cout << "l value" << endl;
}
void f(int&& x)
{
cout << "r value" << endl;
}
int main()
{
int a = 0;
f((int)a);
}
Run Code Online (Sandbox Code Playgroud)
编译器有不同的结果:
我知道下面写的代码是非法的
void doSomething(std::string *s){}
int main()
{
doSomething(&std::string("Hello World"));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
原因是我们不允许获取临时对象的地址.但我的问题是为什么?
让我们考虑以下代码
class empty{};
int main()
{
empty x = empty(); //most compilers would elide the temporary
return 0;
}
Run Code Online (Sandbox Code Playgroud)
公认的答案在这里提到
"通常编译器会将临时和副本构造为两个对象,它们位于内存的完全相同的位置,并避免复制."
根据声明,可以得出结论,临时存在于某个内存位置(因此可能已经采用了它),编译器决定通过在临时存在的同一位置创建就地对象来消除临时对象. .
这是否与临时地址不能采取的事实相矛盾?
我还想知道如何实现返回值优化.有人可以提供与RVO实施相关的链接或文章吗?
我知道有些主题与此类似(例如此).
本主题中给出的示例如下:
std::string & rs1 = std::string();
Run Code Online (Sandbox Code Playgroud)
显然,std :: string()是一个右值.但是,我的问题是为什么s1合法而s2不合法?
const std::string& s1 = "String literal";
std::string& s2 = "String literal";
Run Code Online (Sandbox Code Playgroud)
该标准清楚地表明字符串文字是左值(这是可以理解的,因为它们在技术上是const char*幕后).当我编译s2时,我得到以下内容:
prog.cpp:4:19: error: invalid initialization of non-const reference of type
'std::string& {aka std::basic_string<char>&}' from an rvalue of type
'const char*' std::string& s2 = "String literal";
Run Code Online (Sandbox Code Playgroud)
我理解左值和右值的标准定义是互斥的,所以这可能是编译器的错误吗?我在这个例子中使用gcc 4.9.2.这也是文字真的是xvalue的情况之一吗?
我试图理解C++ 11中的左值和右值.所以我写了一个测试代码:
int x = 10;
int foo() { return x; }
int& bar() { return x; }
int&& baz() { return 10; }
int main() {
int& lr1 = 10; // error: lvalue references rvalue
int& lr2 = x; // ok
int& lr3 = foo(); // error: lvalue references rvalue
int& lr4 = bar(); // ok
int& lr5 = baz(); // error: lvalue references rvalue
int&& rr1 = 10; // ok
int&& rr2 = x; // error: rvalue references …Run Code Online (Sandbox Code Playgroud) 让我们考虑以下代码:
int main() {
int i = 2;
int b = ++i++;
return 3;
}
Run Code Online (Sandbox Code Playgroud)
编译时出现以下错误:
<source>: In function 'int main()':
<source>:3:16: error: lvalue required as increment operand
3 | int b = ++i++;
| ^~
Run Code Online (Sandbox Code Playgroud)
这对我来说听起来很公平。后缀增量的优先级高于前缀增量的优先级,因此代码被解析为int b = ++(i++);,i是右值。因此,错误。
现在让我们考虑带有括号的此变体,以覆盖默认优先级:
int main() {
int i = 2;
int b = (++i)++;
return 3;
}
Run Code Online (Sandbox Code Playgroud)
该代码将编译并返回3。对我来说,这听起来很公平,但似乎与第一个代码矛盾。
问题:为什么(++i)是lvalue当i不成?
谢谢!
更新:上面显示的错误消息来自gcc(x86-64 9.2)。这是确切的渲染: gcc错误
Clang x86-64 9.0.0有一个完全不同的消息: clang错误
<source>:3:13: error: expression is …Run Code Online (Sandbox Code Playgroud) 左值是绑定到存储器的确定区域的值,而右值是表达式值,其存在是临时的,并且不一定是指存储器的确定区域.只要在预期rvalue的位置使用左值,编译器就会执行左值到右值的转换,然后继续进行求值.
http://www.eetimes.com/discussion/programming-pointers/4023341/Lvalues-and-Rvalues
每当我们构造一个临时(匿名)类对象或从函数返回一个临时类对象时,虽然该对象是临时的,但它是可寻址的.但是,对象仍然是有效的右值.这意味着当编译器期望使用左值时,对象是a)可寻址的右值或b)从左值隐式转换为右值.
例如:
class A
{
public:
int x;
A(int a) { x = a; std::cout << "int conversion ctor\n"; }
A(A&) { std::cout << "lvalue copy ctor\n"; }
A(A&&) { std::cout << "rvalue copy ctor\n"; }
};
A ret_a(A a)
{
return a;
}
int main(void)
{
&A(5); // A(5) is an addressable object
A&& rvalue = A(5); // A(5) is also an rvalue
}
Run Code Online (Sandbox Code Playgroud)
我们还知道函数返回的临时对象(在下面的例子中a)是lvalues作为这个代码段:
int main(void)
{
ret_a(A(5));
}
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
int conversion …
在"Lvalues和rvalues",[basic.lval](3.10)中,C++标准包含一个类型列表,使得通过这种类型的glvalue"访问对象的存储值"是有效的(第10段) .具体来说,它说:
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
对象的动态类型,
[关于简历和签名/未签名的一些不重要的细节]
聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(递归地,包括子聚合或包含联合的元素或非静态数据成员),
[更多东西]
"聚合"规则到底意味着什么?如何通过某些常规聚合类型的glvalue访问对象的存储值?!
我想象的是这样的:
int a = 10; // my "stored value"
struct Foo { char x; float y; int z; bool w; }; // an aggregate
reinterpret_cast<Foo&>(a).y = 0; // ???
Run Code Online (Sandbox Code Playgroud)
最终的强制转换是否会产生"包含动态类型的聚合类型"的glvalue a,从而使其有效?
我尝试A按如下方式定义一个类:
template< typename T >
class A
{
public:
A( T elem )
: _elem( elem )
{}
private:
TYPE _elem; // "TYPE" should be either "T" in case "elem" is an r-value or "T&" in case "elem" is an l-value.
};
Run Code Online (Sandbox Code Playgroud)
在这里,我希望_elem有一个类型T,以防构造函数的参数elem是一个r值或者T&case中的类型elem是一个l值.
有谁知道这是如何实现的?
为什么不能将rvalues转换为左值?但是可以在相反方向进行转换.技术上rvalues确实有内存地址,不是吗?
例子:
typedef enum Color
{
RED,
GREEN,
BLUE
} Color;
void func(unsigned int& num)
{
num++;
}
int main()
{
Color clr = RED;
func(clr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译时出现以下错误:
<source>: In function 'int main()':
<source>:16:9: error: cannot bind non-const lvalue reference of type 'unsigned int&' to an rvalue of type 'unsigned int'
func(clr);
^~~
Run Code Online (Sandbox Code Playgroud)
我认为clr我传递给的变量 ( )func(unsigned int&)是一个左值。我可以获得的地址clr并可以为其分配另一个值。当我尝试将它传递给 时,为什么它会变成右值func(unsigned int&)?