C++오른쪽 값 참조

개술
C++에서 상수,변수 또는 표현 식 은 왼쪽 값(lvalue)이나 오른쪽 값(rvalue)이 어야 합 니 다.
왼쪽 값:임시 적 이지 않 습 니 다.등호 의 왼쪽 이나 오른쪽 에 나타 날 수 있다.비상 왼쪽 값 과 상수 왼쪽 값 으로 나 눌 수 있다.

오른쪽 값:임시(이름 을 구하 지 않 고 현재 구문 에서 만 유효 하 며 주 소 를 찾 을 수 없습니다).등호 오른쪽 에 만 나타 날 수 있 습 니 다.비상 량 오른쪽 값 과 상수 오른쪽 값 으로 나 눌 수 있다.

왼쪽 값 참조:왼쪽 값 에 대한 인용 은 왼쪽 값 참조 입 니 다.비상 왼쪽 값 참조 와 상수 왼쪽 값 참조 로 나 눌 수 있 습 니 다.

주:상수 왼쪽 값 인용 은'만능'의 인용 유형 으로 모든 유형의 값 에 연결 할 수 있 습 니 다.비상 왼쪽 값,상수 왼쪽 값,비상 오른쪽 값 과 상수 오른쪽 값 을 포함 합 니 다.
오른쪽 값 참조(Rvalue References):오른쪽 값 에 대한 참조 가 오른쪽 값 참조 입 니 다.비상 량 오른쪽 값 인용 과 상수 오른쪽 값 인용 으로 나 눌 수 있다.

임시 대상 의 오른쪽 값 입 니 다.수명 주기 가 짧 습 니 다.일반적으로 현재 표현 식 을 실행 한 후에 방출 됩 니 다.
이 값 을 오른쪽 값 에 인용 함으로써 비 싼 복사 작업 을 하지 않 은 상태 에서'계속'되 어 생명 주기 가 오른쪽 값 참조 유형 변수의 생명 주기 와 똑 같이 길 게 할 수 있 습 니 다.
오른쪽 값 참조 의 두 가지 기본 특성:이동 의미(Move Semantics)와 완벽 한 퍼 가기(Perfect Forwarding)
이동 의미(Move Semantics)
자원 을 한 대상 에서 다른 대상 으로 옮 길 수 있 습 니 다.불필요 한 임시 대상 의 생 성,복사,폐 기 를 주로 해결 합 니 다.
이동 구조 함수 MyClass(Type&a):구조 함수 인자 가 오른쪽 값 일 때 복사 구조 함수 MyClass(const Type&a)가 아 닌 이동 구조 함 수 를 우선 사용 합 니 다.
이동 할당 연산 자 Type&operator=(Type&&a):할당 이 오른쪽 값 일 때 할당 연산 자 Type&operator=(const Type&a)를 복사 하지 않 고 이동 할당 을 우선 사용 합 니 다.

#include <iostream>
#include <string>
#include <utility>

struct MyClass
{
    std::string s;
    MyClass(const char* sz) : s(sz) 
    {
        std::cout << "MyClass sz:" << sz << std::endl;
    }
    MyClass(const MyClass& o) : s(o.s) 
    { 
        std::cout << "copy construct!
"; } MyClass(MyClass&& o) noexcept : s(std::move(o.s)) { std::cout << "move construct!
"; } MyClass& operator=(const MyClass& other) { // copy assign std::cout << "copy assign!
"; s = other.s; return *this; } MyClass& operator=(MyClass&& other) noexcept { // move assign std::cout << "move assign!
"; s = std::move(other.s); return *this; } static MyClass GetMyClassGo(const char* sz) { MyClass o(sz); // : NRVO return o; } }; void func0(MyClass o) { std::cout << o.s.c_str() << std::endl; } void func1(MyClass& o) { std::cout << o.s.c_str() << std::endl; } void func2(const MyClass& o) { std::cout << o.s.c_str() << std::endl; } void func3(MyClass&& o) { std::cout << o.s.c_str() << std::endl; } int main(int arg, char* argv[]) { MyClass a1("how"); MyClass a2("are"); a2 = a1; // copy assign :a1 a2 = MyClass("you"); // move assign :MyClass("you") MyClass a3(a1); // copy construct :a1 MyClass&& a4 = MyClass::GetMyClassGo("go"); // move construct : MyClass::GetMyClassGo() MyClass a5 = MyClass::GetMyClassGo("china"); // move construct : MyClass::GetMyClassGo() ; a5 MyClass a6("let"); MyClass a7("it"); MyClass a8("go"); MyClass a9("!"); func0(a6); // copy construct func1(a7); func2(a8); //func3(a9); // error: func0(MyClass::GetMyClassGo("god")); // move construct : MyClass::GetMyClassGo() ; foo0 //func1(MyClass::GetMyClassGo("is")); // error: func2(MyClass::GetMyClassGo("girl")); // move construct : MyClass::GetMyClassGo() func3(MyClass::GetMyClassGo("!")); // move construct : MyClass::GetMyClassGo() return 0; }
주:테스트 이상 코드 는 반드시 C++컴 파 일 러 최적화 기술 인 RVO,NRVO 와 복사 생략 을 닫 아야 합 니 다.
std::move 를 사용 하여 이동 의 미 를 실현 합 니 다.
왼쪽 값 이나 오른쪽 값 을 오른쪽 값 참조 로 강제로 바 꿉 니 다.주:UE4 에서 MoveTemp 템 플 릿 함수 에 대응
std::move(en chs)는 아무것도 이동 하지 않 고 대상 의 상태 나 소유권 을 한 대상 에서 다른 대상 으로 이전 합 니 다.주:이동 만 할 뿐 메모리 의 이전 이나 메모리 복사 가 없습니다.
① 기본 유형(예 를 들 어 int,double 등)이 std::move 에 의 해 이동 한 후에 그 수 치 는 변화 가 없 을 것 이다.
② 복합 형식 이 std::move 로 이동 한 후 정의 되 지 않 았 지만 효과 적 인 상태(대부분의 구성원 함수 가 의미 가 있 음)예 를 들 어 표준 라 이브 러 리 의 용기 류 대상 이 이동 하면 빈 용기 가 됩 니 다.
완벽 한 퍼 가기(Perfect Forwarding)
템 플 릿 함수 에 대해 서 는 한 그룹의 매개 변 수 를 다른 함수 에 그대로 전달 할 수 있 습 니 다.
왼쪽 값,오른쪽 값,const 여부 가 변 하지 않 습 니 다.다음 과 같은 세 가지 장점 을 가 져 옵 니 다.
① 왼쪽,오른쪽 값 의 속성 확보
② 불필요 한 복사 작업 을 피한다.
③ 모드 함수 가 왼쪽 값,오른쪽 값,const 의 매개 변수 로 서로 다른 과부하 를 실현 하 는 지 피해 야 한다.
만능 참조(유 니 버 설 references,퍼 가기 참조)는 특수 한 템 플 릿 참조 유형 으로 오른쪽 값 참조 문법 형식 을 사용 합 니 다(그러나 오른쪽 값 참조 가 아 닙 니 다).예:templatevoid func(T&&t){}
T&t 는 자동 형식 추정 이 발생 할 때 미 정 참조 유형(유 니 버 설 references)입 니 다.T 는 들 어 오 는 매개 변수 t 가 오른쪽 값 인지 왼쪽 값 인지 에 달 려 있 습 니 다.오른쪽 값 은 T&&&를 거 쳐 오른쪽 값 으로 인용 되 고 왼쪽 값 은 T&&&를 거 쳐 왼쪽 값 으로 인용 된다.
std::move 는 전 능 인용 으로 이 루어 집 니 다.그 정 의 는 다음 과 같다.

template <typename T>
typename remove_reference<T>::type&& move(T&& t)
{
    return static_cast<typename remove_reference<T>::type &&>(t);
}


/*****************************************
std::remove_reference           

std::remove_reference<T &>::type ---> T
std::remove_reference<T &&>::type ---> T
std::remove_reference<T>::type ---> T
******************************************/
//   ,      
template <typename T> struct remove_reference{
    typedef T type;  //  T      type
};
 
//       ,            
template <class T> struct remove_reference<T&> //    
{ typedef T type; }
 
template <class T> struct remove_reference<T&&> //    
{ typedef T type; }
① t 가 왼쪽 값 일 때 U&move(U&t)로 펼 쳐 집 니 다.주:오른쪽 값 참조 유형 변수 도 왼쪽 값 입 니 다.
② t 가 오른쪽 값 일 때 U&move(U&t)로 펼 쳐 집 니 다.
마지막 으로 static 을 통 해cast<>강제 형식 변환 을 진행 하여 오른쪽 값 참조 로 되 돌려 줍 니 다.주:static캐 스 트 가 유형 변환 을 사용 할 수 있 는 이 유 는 removereference:type 템 플 릿 은 T&,T&의 인용 을 제거 하고 구체 적 인 유형 T(템 플 릿 편 특 화)를 가 져 옵 니 다.
인용 접 기
법칙:왼쪽 값 인용 을 포함 하 는 것 은 왼쪽 값 인용 이 고,그렇지 않 으 면 오른쪽 값 인용 이다.

std::forward 를 사용 하여 매개 변수의 완벽 한 퍼 가기 를 실현 합 니 다.그 정 의 는 다음 과 같 습 니 다(en chs).

template <typename T>
T&& forward(remove_reference_t<T>& arg) // forward an lvalue as either an lvalue or an rvalue
{ 
    return static_cast<T&&>(arg);
}

template <typename T>
T&& forward(remove_reference_t<T>&& arg) // forward an rvalue as an rvalue
{ 
    static_assert(!is_lvalue_reference_v<T>, "bad forward call");
    return static_cast<T&&>(arg);
}
마지막 으로 static 을 통 해cast<>인용 접 기 를 하고 형식 변환 을 강제 한 후 그대로 전송 파 라미 터 를 실현 합 니 다.주:UE4 에서 Forward 템 플 릿 함수 로 대응

void bar(int& a, int&& b)
{
    int c = a + b;
}

void func(int a, int&& b)
{
    int c = a + b;
}

template <typename A, typename B>
void foo(A&& a, B&& b) { // a, b          
    bar(std::forward<A>(a), std::forward<B>(b)); //  std::forward    ,  a,b       
}

int main(int arg, char* argv[])
{
    int a = 10;

    foo(a, 20); //    void foo(int& a, int&& b),  std::forward     ,    void bar(int& a, int&& b)  

    func(std::forward<int>(a), std::forward<int&&>(30)); //   std::forward     ,    void func(int a, int&& b)  

    return 0;
}
이상 은 C++오른쪽 값 참조 에 대한 상세 한 내용 입 니 다.C+오른쪽 값 참조 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기