有人可以向R-Value解释或指出某种解释吗?我不确定它是什么,我的项目必须加入它.下面是R-Value的演示(第一部分是r_string.hpp):
#include <algorithm>
#include <iostream>
template <typename CHAR_T = char>
class basic_rstring {
public:
typedef CHAR_T value_type;
typedef CHAR_T* pointer_type;
typedef CHAR_T const* pointer_const_type;
private:
pointer_type _data;
std::size_t _length;
public:
basic_rstring() : _data(nullptr), _length(0)
{
std::cout << "Default ctor\n";
}
basic_rstring( pointer_const_type s )
: _data( nullptr )
, _length( 0 )
{
std::cout << "Literal ctor: " << s << std::endl;
_length = strlen( s );
_data = new value_type[ _length + 1 ];
std::copy( s, s + _length …Run Code Online (Sandbox Code Playgroud) 在C++ 11中,我们可以定义复制和移动构造函数,但是它们都允许在同一个类中?如果是这样,你如何消除他们的使用歧义?例如:
Foo MoveAFoo() {
Foo f;
return f;
}
Run Code Online (Sandbox Code Playgroud)
以上是副本吗?一个动作?我怎么知道?
在C++ 11中,值参数(和其他值)在返回时享受隐式移动:
A func(A a) {
return a; // uses A::A(A&&) if it exists
}
Run Code Online (Sandbox Code Playgroud)
至少在MSVC 2010中,右值参考参数需要std::move:
A func(A && a) {
return a; // uses A::A(A const&) even if A::A(A&&) exists
}
Run Code Online (Sandbox Code Playgroud)
我认为内部函数,右值引用和值的行为类似,唯一的区别是在值的情况下,函数本身负责销毁,而对于右值引用,责任在外面.
在标准中对待它们的动机是什么?
C++标准,主要在第5章,标题为表达式,定义哪些表达式是左值,哪些是右值.我读过那一章,我相信我可以正确区分左值和右值.
然而,在我阅读好的C++书籍和/或标准之前,我曾经认为左值是可以站在赋值左侧的东西,右值是不能的.显然,这个天真的定义有很多反例.一段时间后,我认为左值是一个有地址的东西,右值是没有的东西.这也似乎有一些反例,例如,一些临时物体,显然,它们确实有一个地址.
我的一个朋友问我什么是左值,什么是左值.我告诉他大概是什么,他要求一个更完整的答案.我告诉他去读标准.他拒绝骚扰他的大脑,并说他确信必须有一些必要和充分条件才能成为一个左右.
在那儿?
例如,左值是非const引用可以绑定的值.但这个并不令人满意.我正在寻找一些更明显的东西,这些东西很容易解释,而不需要考虑每种表达类型......
我希望这个问题很明确.
前提:
C++ 11 Standard将表达式分为三个不相交的值类别:lvalues,xvalues和prvalues(第3.10/1节).此处提供了对哪些值类别的解释.
我正在努力弄清楚不同运营商对其操作数的价值类别的要求是什么.第3.10/1段规定:
[...]每个表达式都属于此分类法中的基本分类之一:lvalue,xvalue或prvalue.表达式的此属性称为其值类别.[注意:第5章中对每个内置运算符的讨论表明了它产生的值的类别以及它所期望的操作数的值类别.例如,内置赋值运算符期望左操作数是左值,右操作数是prvalue并产生左值作为结果.用户定义的运算符是函数,它们期望和产生的值的类别由它们的参数和返回类型决定. - 尾注]
尽管上面的说明声称,第5条并不总是非常清楚运营商的操作数的价值范畴.例如,关于赋值运算符的操作数的值类别(第5.17/1段),这就是所说的:
赋值运算符(=)和复合赋值运算符都是从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.对于不确定序列的函数调用,复合赋值的操作是单个评估.[注意:因此,函数调用不应介入左值到右值的转换和与任何单个复合赋值运算符相关的副作用. - 尾注]
合适的操作数怎么样?
整个5.17节中不再出现"rvalue"和"lvalue"字样.虽然第3.10/1段中的注释明确指出内置赋值运算符期望将prvalue作为右操作数,但在第5.17节中没有明确提到.甚至5.17/1的最后一个注释,提到左值到右值的转换,似乎暗示rvalues是以某种方式预期的(否则转换的需要是什么?),但笔记毕竟是非规范性的.
涉及其他运算符的部分,包括乘法运算符和加法运算符,通常对其操作数的值类别保持沉默.我在标准中找不到任何"默认语句",声明如果没有另外指定,内置运算符的操作数是rvalues.因此,问题.
题:
很高兴参考C++ 11标准.
什么是右值,左值,x值,glvalues和prvalues?对rvalues/lvalues的分类进行了很好的概述,最近对该问题的回答之一(/sf/answers/668701631/)强调了prvalues"喜欢"旧式rvalues的观点而新的xvalues允许"左值"行为.
但是,请考虑以下代码:
class X {};
X foo() { return X(); }
int main()
{
foo() = X(); // foo() is a prvalue that successfully appears on the lhs
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,表达式foo()是出现在左侧的prvalue,并接受赋值.
这让我思考 - "xvalues"与"prvalues"的逻辑不同,因为xvalues(它们是glvalues)可能出现在左侧,似乎被这个例子打破了.在这里,我们有一个prvalue - 这不是一个glvalue - 成功地出现在lhs并接受任务.
(注意:在POD的情况下,上面的例子不会编译,所以对于POD,xvalues和prvalues之间的区别似乎是有意义的.因此,这个问题特别针对非POD类型.)
那么,xvalue和prvalue之间的允许使用或行为的真正区别是什么,这需要将这种区别写入标准?差异的一个例子是一个很好的替代答案.
附录
Pubby的评论是正确的.prvalue的生命周期由编译器扩展,但xvalue的生命周期不是.
所以,这是一个问题的答案:
请考虑以下代码:
// ***
// Answer to question, from Pubby's comment
// ***
class X
{
public:
X() : x(5) {}
int x;
};
X foo() { return X(); }
X&& goo() { return …Run Code Online (Sandbox Code Playgroud) 假设我有一个(普通的)类,它是可移动构造和可移动分配但不可复制构造或可复制分配:
class movable
{
public:
explicit movable(int) {}
movable(movable&&) {}
movable& operator=(movable&&) { return *this; }
movable(const movable&) = delete;
movable& operator=(const movable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
这很好用:
movable m1(movable(17));
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,因为m1它不是右值:
movable m2(m1);
Run Code Online (Sandbox Code Playgroud)
但是,我可以包m1中std::move,它投射到一个右值引用,以使其工作:
movable m2(std::move(m1));
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在,假设我有一个(同样微不足道的)容器类,它包含一个值:
template <typename T>
class container
{
public:
explicit container(T&& value) : value_(value) {}
private:
T value_;
};
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用:
container<movable> c(movable(17));
Run Code Online (Sandbox Code Playgroud)
编译器(我试过clang 4.0和g ++ 4.7.2)抱怨我正在尝试movable在container初始化列表中使用已删除的复制构造函数.同样,包裹value在std::move使得它的工作:
explicit container(T&& value) : value_(std::move(value)) {} …Run Code Online (Sandbox Code Playgroud) 我读的越多,我就越困惑.
相关问题的最后一个问题与我的问题最接近,但是我对所有关于对象生命周期的问题感到困惑,尤其是 - 只读或不读.
直截了当.如我错了请纠正我.
这很好,gcc没有发出警告,我正试图" 通过" 读取类型T(uint32_t)char*:
uint32_t num = 0x01020304;
char* buff = reinterpret_cast< char* >( &num );
Run Code Online (Sandbox Code Playgroud)
但这是"坏"(也是一个警告),我正在尝试"反过来":
char buff[ 4 ] = { 0x1, 0x2, 0x3, 0x4 };
uint32_t num = *reinterpret_cast< uint32_t* >( buff );
Run Code Online (Sandbox Code Playgroud)
第二个如何与第一个不同,特别是当我们谈论重新排序指令(用于优化)时?另外,添加const不会以任何方式改变这种情况.
或者这只是一条直接规则,它明确指出:"这可以在一个方向完成,但在另一个方向不能完成"?我在标准中找不到任何相关内容(特别是在C++ 11标准中搜索过).
C和C++是否相同(因为我读了一条评论,暗示它与2种语言不同)?
我曾经union"解决"这个问题,但仍然看起来并非 100%正常,因为标准无法保证(这表明我只能依赖于最后一次修改的值union).
所以,经过大量阅读,我现在更加困惑.我想只是memcpy"好"的解决方案?
相关问题:
编辑
现实世界的情况:我有一个第三方库(http://www.fastcrypto.org/),它计算UMAC并返回值char[ 4 ].然后我需要将其转换为uint32_t.而且,顺便说一句,lib使用的东西((UINT32 …
我知道类型this是prvalue("纯"rvalue)指针,并且它可以通过附加关键字成为指向const的指针和/或指向volatile的指针(影响对其实例变量的访问)const或者volatile它所属的函数定义的末尾.
我也知道this有时(错误地)将其描述为一个const指针,也许是为了说"你不能做出任务this".作为右值,它本质上是不可分配的,因此不需要constrvalue 的概念.
我也知道在C++ 11中,有些情况下rvalue或左值会影响调用解析,但我试图解决这些可能性,而且我不确定是否存在实际情况调用分辨率this是一个右值指针而不是一个const左值指针.
从程序员的角度来看,是否存在这种区别产生真正差异的情况,例如可以使用const左值指针而不能使用左值指针的上下文,其中可以使用左值指针不能使用const左值指针,或者差异会影响呼叫解决?