【问题标题】:What exactly is an R-Value in C++?C++ 中的 R 值到底是什么?
【发布时间】:2023-03-16 05:02:01
【问题描述】:

有人可以解释或指出某种解释,什么是 R 值吗?我不太确定它是什么,我的项目必须包含它。下面是 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 + 1, _data );
    }

    basic_rstring( basic_rstring const& s )     
        : _data( nullptr )
        , _length( s._length )
    {
        std::cout << "Copy ctor: " << s.c_str() << std::endl;
        _data = new value_type [ _length + 1 ];
        std::copy( s._data, s._data + s._length + 1, _data );
    }

    basic_rstring( basic_rstring && s )     //move constructor
        : _data( s._data )
        , _length( s._length )
    {
        std::cout << "Move ctor: " << s.c_str() << std::endl;
        s._data = nullptr;
        s._length = 0;
    }

    ~basic_rstring()
    {
        if( _data )
            std::cout << "dtor: " << _data << "\n";
        else 
            std::cout << "NULL dtor\n";
        delete [] _data;
    }

    basic_rstring& operator = ( basic_rstring const& s );
    basic_rstring& operator = ( basic_rstring && s )
    {
        std::cout << "RValue assignment: " << s.c_str();
        if( _data )
            std::cout << " deleting...." << std::endl;
        else 
            std::cout << " no delete..." << std::endl;
        delete [] _data;
        _data = s._data;
        s._data = nullptr;
        _length = s._length;
        s._length = 0;
        return *this;
    }

    pointer_const_type c_str() const { return _data; }

};

template <typename CHAR_T>
basic_rstring<CHAR_T>& basic_rstring<CHAR_T>::operator = ( basic_rstring const& s )
{
    std::cout << "Copy assignment: " << s.c_str() << std::endl;
    pointer_type newData = new value_type [ s._length + 1 ];
    std::copy( s._data, s._data + s._length + 1, newData );
    _length = s._length;
    delete [] _data;
    _data = newData;
    return *this;
}

typedef basic_rstring<char> String;
typedef basic_rstring<wchar_t> wString;


#define _SCL_SECURE_NO_WARNINGS
#include "Rstring.hpp"
using namespace std;
#define BOOST_TEST_MODULE move_test
#include <boost/test/unit_test.hpp>

template <typename T_>
void old_swap( T_& a, T_&b ) 
{
    T_ hold = a;
    a = b;
    b = hold;
}

BOOST_AUTO_TEST_CASE( stuff )
{
    String s("Bert");
    String t("Ernie");
    cout << "Old swap" << endl;
    old_swap(s,t);
    BOOST_CHECK( !strcmp( "Bert", t.c_str() ) );
    BOOST_CHECK( !strcmp( "Ernie", s.c_str() ) );

    cout << "New swap" << endl;
    swap(s,t);
    BOOST_CHECK( !strcmp( "Bert", s.c_str() ) );
    BOOST_CHECK( !strcmp( "Ernie", t.c_str() ) );

    cout << "\nDone." << endl;

}

【问题讨论】:

  • @Nicol:他问的是右值,而不是右值引用。所以我更喜欢这个问题。但绝对是个骗子。
  • 我完全不同意关闭。提出一个基本问题的 OP 将不会受到建议副本中的高级讨论的帮助。问题不在一个层次。这个问题是关于一个基本的解释。 Nicol 提出的副本是先进的,只是模糊关联,它是无关紧要的。 Ben 提议的副本是针对语言律师,而不是针对 OP。它们不是重复的。这个问题不应该被关闭。关闭对任何人都没有帮助。

标签: c++ c++11


【解决方案1】:

“有人能解释一下什么是 R-Value,或者给我一些解释吗?我不太确定它是什么”

lvalue 一词最初指的是一个表达式,它可能是赋值的left。相应地,一个 rvalue (虽然我记得 C89 标准没有使用这个术语),最初正好相反:一个表达式不能是赋值的左侧,但可以只是右边

C++11 通过添加一些更细微的术语使这变得复杂,但让我们专注于 C++03 的含义。

例如,如果你有

int x;

那么赋值x = 42就OK了,所以x是一个左值表达式。

作为反例,x+0 = 42 的赋值不正确,所以x+0 是一个右值表达式。

表达式2+2也是如此,它是一个右值表达式。

因此,如果要求您的程序应该包含一个右值,那么只需编写 2+2 或例如(更高级)6*7,在main

原来的 C 没有const。在 C++ 中,使用 const,您必须忽略 const,以便将表达式指定为左值或右值。关键点是保证的表达式是否引用内存中的对象,具有地址的对象:如果是,则表达式是左值。

引用类型意味着左值,因为引用类型的表达式必然引用具有内存地址的对象,即该表达式是左值。

但是,除了引用之外,类型和左值/右值之间没有任何联系。例如,xx+0 都是int 类型的表达式,它们产生相同的int 值。但前者是左值表达式,而后者是右值表达式。

作为一般规则,如果你可以应用内置地址运算符,那么它是一个左值表达式,否则它是一个右值表达式。

【讨论】:

  • C 标准对“左值”的定义有着曲折的历史; C90 和 C99 的定义都有严重的问题。 C11 将左值定义为“一个表达式......可能指定一个对象”(“可能”意味着*ptr 是一个左值,即使ptr==NULL 也是如此)。 C11 的修改措辞是我的想法。
  • @KeithThompson:您是否知道您的 SO 个人资料中的链接已失效?
  • @CamJackson:哪一个? GitHub 和职业链接都对我有用。
  • @Cheers 和 hth。 - 阿尔夫,谢谢。我现在有了更好的理解。该项目是创建一个方形列表数据结构,我现在认为需要假设 C++11 && 移动语义?
  • C 标准仅在非规范脚注中提及术语“右值”:“有时称为“右值”的东西在本国际标准中被描述为“表达式的值”。
【解决方案2】:

rvalue 一词源于其历史背景 --- 它只能出现在赋值的右侧,而不是 lvalue它可以放在作业的左侧。因此,命名变量(例如x)是左值,但文字整数(例如42)是右值。

然而,在现代 C++ 中,它比这更微妙。

在 C++ 中,右值是未命名的对象或此类对象的成员,它不是引用。

一些例子:

std::string s;

std::string foo(){ return "foo";}

struct X {
    std::string s;
};

std::string& bar() {return s;}

void baz(std::string const& x){}

s=std::string("hello"); // 1
s=foo();                // 2
std::string s2=bar();   // 3
baz("hello");           // 4
s=X().s;                // 5

在 (1) 中,从字符串字面量创建的临时 std::string 对象是一个右值。

在(2)中,foo()返回的对象是一个右值。

在 (3) 中,bar() 返回一个引用,因此没有右值。

在 (4) 中,从字符串字面量隐式创建的临时 std::string 对象是一个右值。

在 (5) 中,临时 X 对象是右值,因此 s 成员也是。

诸如x+3 之类的表达式通常会产生一个临时值,因此它是一个右值。但是,如果使用运算符重载将返回类型更改为引用,则结果是左值。

【讨论】:

    【解决方案3】:

    右值和左值

    在解释这两个符号之前,让我们检查一下所谓的 MovableIdentity

    身份:- 简而言之,任何有名字的东西我们都可以指向或引用来知道它是相同的值还是不同的值

    移动:- 简而言之,任何内容可以从一个地方或内存移动到另一个地方的东西

    左值是那些具有标识的值,因此我们可以指向它或引用它,但不能移动它这些被称为经典值

    Rvalue 是可移动的(无论是否具有标识)这些包含支持移动的临时值或 ADT

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-06
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-27
      相关资源
      最近更新 更多