Rvalue Reference In Cxx11

Rvalue Reference In Cxx11
author: vector03
mail:   [email protected]
1. copy constructor 및 임시 객체
함수가 대상을 되돌릴 때
CFoo getFoo(args...) {
    CFoo ret(...);
    ...
    ...
    return ret;
}

CFoo의 copy constructor가 다음과 같은 경우
CFoo::CFoo(const CFoo& foo) {
        // resource copy
        ...
}

코드 세그먼트,
{
    ...
    CFoo foo(getFoo(...));
    ...
}

위의 상황을 고려하면 대상foo는 구성할 때 getFoo 함수가 되돌아오는 임시 대상의 내용을 복사합니다.
CFoo 내부에 대량의 자원이 존재한다고 가정하면 다음에 일련의 deep copy 동작이 있을 것이다.사실
끝난 후 임시 대상은 아무런 의미가 없다. 이것은 cxx 대상을 구성할 때 피하기 어려운 저효과 초기이다
방식을 바꾸다.
2. move semantic
cxx11에서 모브의 의미를 통해copy constructor를 모브 constructor로 바꿀 수 있습니다.
예를 들어, CFoo의 copy construct는 다음과 같이 바꿀 수 있습니다.
    CFoo::CFoo(const CFoo& foo) {
        // 1. Release the resource the object already had.
        // 2. Copy the resource handle from the source to the target object.
        // 3. Set resource handle of the source object to NULL.

    }

move constructor를 통해 소스object의 자원을 내부에서 훔쳐왔습니다.
move의 의미는 물론 좋지만 어떤 때는 전통적인 copy construct가 필요합니다. 예를 들어
    CFoo a();

    CFoo b(a);

이런 상황에서 모브의 의미를 사용하면 문제를 일으킬 수 있다. 왜냐하면 대상 a가 b에게 전달된 후에
내부에 보이지 않는 변화가 생겼다.만약 후속으로 a를 인용한다면 매우 위험할 것이다.
아래의 상황은 더욱 합리적이고,
    CFoo a(getFoo());

또는
    CFoo a();
    CFoo b();
    CFoo c(a + b);

여기에서 함수에서 되돌아오든지, 연산자를 다시 불러온 후에 생성된 대상은 모두 익명으로 임시적이다.생명 때문에
주기가 매우 짧기 때문에 내부 자원을 이전하는 것은 현명한 행동이다.
이전의 cxx 컴파일러에 대해 말하자면, 현재copy/move constructor를 호출해야 한다고 판단하는 것은 어려운 문제이다.
이 의미를 알 수 있는 더 좋은 수단이 없기 때문이다.그래서 cxx11에 rvalue reference가 추가되었습니다.
3. lvalue and rvalue
서면에서, 부치 연산자 왼쪽의 표현식은 lvalue이고, 오른쪽의 표현식은 rvalue이다.대부분의 경우 문제없지만,
하지만 예외도 있다.예를 들어, 수조명은 부수 연산 왼쪽에 있지만, 한 수조명에 직접 부수할 수 없다. 왜냐하면
상수 주소입니다.
char name[] = "foo";  //ok
char* buff = "foo";
name = buff;          //err,  .


또 다른 lvalue와 rvalue의 정의는 lvalue가 하나의 메모리 공간을 가리키며 이 메모리를 가리키는
포인터, 이외의 값은 모두 rvalue입니다.
// lvalue sample
int a = 10;     //ok, a lvalue
int* p = &a;    //ok,  a 
int& foo();
foo() = 10;     //ok, foo() lvalue
int* p = &foo();    //ok,  lvalue 

// rvalue sample
int a = 10;
int b = 3;
a * b = 15;     //err, a * b rvalue
int bar();
int* p1 = &bar();    //err, bar() rvalue,  
bar() = a;      //err,  ,  rvalue 


일반적으로 두 대상의 연산 결과나 대상이 되돌아오는 값으로 rvalue라고 볼 수 있다.왜냐하면 이런 상황에서.
대상의 주소는 종종 레지스터에 저장되며, 일반적인 방법으로는 그 주소를 얻을 수 없다.
4. rvalue reference
rvalue reference는 T&.이것은 T&의 인용이 아니므로 cxx에는 이중 인용의 개념이 존재하지 않습니다.
T&를 구분하는 데 대응하는 것은 lvalue reference입니다.
rvalue reference가 있으면 각각copy/move constructor를 실현할 수 있고,compiler는 전송된
대상의 성질은 컴파일 단계에서 적당한 재부팅을 선택합니다.
CFoo::CFoo(CFoo const & foo) {
    // impliment copy construct
    ......
}

CFoo::CFoo(CFoo&& foo) {
    // impliment move construct
    ......
}

CFoo foo;
CFoo foo1(foo);      //  copy construct
CFoo getFoo();
CFoo foo2(getFoo()); //  move construct

또한 lvalue와 rvalue가 동시에 존재하는 경우 컴파일러는 rvalue의 버전을 우선선택합니다.
전제는 네가 이미 두 가지 판본을 실현했다는 것이다.
CFoo(Cfoo &foo)만 실현되면 lvalue만 사용할 수 있습니다.
CFoo(CFoo& foo);
CFoo foo;
CFoo foo1(foo);     //ok, foo lvalue
CFoo foo2(CFoo());  //error, CFoo() rvalue

CFoo(CFoo const &foo)가 실현되면 이전과 마찬가지로 lvalue도 사용할 수 있고 rvalue도 사용할 수 있다.
컴파일러는 copy/move construct를 구분할 수 없습니다.
CFoo(CFoo const & foo);
CFoo foo;
CFoo foo1(foo);     //ok, foo lvalue
CFoo foo2(CFoo());  //ok,  rvalue

rvalue reference를 동시에 실현해야만 컴파일러가 overload의 다른 construct를 정확하게 할 수 있습니다.
CFoo(CFoo const & foo);
CFoo(CFoo&& foo);
CFoo foo;
CFoo foo1(foo);     // CFoo(const Foo& foo)
CFoo foo2(CFoo());  // CFoo(CFoo&& foo)

마지막으로 rvalue reference 버전만 실현하면 rvalue만 받을 수 있습니다.
CFoo(CFoo&& foo);
CFoo foo;
CFoo foo2(foo);     //err, foo lvalue

5. 강제 rvalue reference
때때로 특정한 수요 때문에 우리는 lvalue에 대해서도 모브의 의미를 사용하기를 원할 수도 있다(자신이 무엇을 하고 있는지 명확히 하는 전제에서).
cxx11에서 std::move()를 도입하여 lvalue에 대한 rvalue reference를 실현했습니다.
move () 자체는 아무것도 옮기지 않습니다. 사실상 대상을 moveable로 바꾸는 데 의미가 있습니다.move () 의 역할을 거친 lvalue
rvalue가 될 수 있어요.
CFoo(CFoo&& foo);
CFoo foo;       //foo lvalue
CFoo foo1(foo)  //err,  lvalue
CFoo foo1(std::move(foo));  //ok, move lvalue rvalue.  foo .

이런 강제rvalue reference는 우원과 같이 모두 현재 체계에 대한 파괴로 편리함과 성능을 가져오는 동시에 일정한
부정적인 작용.사용 시 별도의 주의가 필요합니다.
6. rvalue reference는 rvalue입니까, 아니면 lvalue입니까?
만약 다음과 같은 호출이 있다면,
CFoo::CFoo() {}

CFoo::CFoo(CFoo const & foo) {
    cout << "lvalue copy construct!" << endl;
}

CFoo::CFoo(CFoo&& foo) {
    cout << "rvalue copy construct!" << endl;
}

void testFoo(CFoo&& foo) {
    CFoo foo1(foo);
}

int main(int argc, char **argv) {
    CFoo foo();
    CFoo foo1(std::move(foo));
    return 0;
}   

최종적으로 인쇄됩니까? lvalue copy construct입니까? 아니면 rvalue copy construct입니까?
답은 집행 결과가 전자라는 것이다.
그러나 나는 분명히 모브의 의미로foo를 rvalue로 강제했는데 왜 마지막에 lvalue를 집행했을까?이것은 cxx표준위원회가
rvalue reference를 설정할 때 rvalue reference는 lvalue이자 rvalue(또는 xvalue라고 부른다)로 정의됩니다.
rvalue reference가 인용한 대상의 익명 여부를 구체적으로 보십시오.익명이면 rvalue reference
rvalue로 표현하지 않으면 lvalue로 표현합니다.
위의 demo에서testFoo는 CFoo & & 유형의 매개 변수를 받아들이지만 CFoo foo 1 대상에게 전달될 때 익명이 아니기 때문에
그러므로 lvalue로 표현된다.CFoo의 lvalue 버전 copy construct가 호출됩니다.만약 이렇게 수정한다면,
void testFoo(CFoo&& foo) {
    CFoo foo1(std::move(foo));
}

전송된 인삼foo를 rvalue로 강제하고 출력은 또 다른 결과입니다.
유사한 예로는 부류와 자류 사이도 있다.만약 이런 부류가 존재한다면,
Base(Base&& o);

그 자류가 이렇게 계승된다면,
Derived(Derived && o) : Base(o) {
    // Derived specific
    ......
}

이곳은 실제로는 번역할 수 없다.부모 클래스의 move constructor를 호출하는 것이지만 Base에 전달되는 매개 변수 때문에
익명이 아닙니다. rvalue reference는 사실상 lvalue입니다. 따라서 Base의 lvalue 버전을 호출합니다.... 하지 않았기 때문에
lvalue 버전의 Base constructor를 다시 불러와서 컴파일에 실패했습니다.여기에는 다음과 같은 수정을 해야 하는데,
Derived(Derived&& o) : Base(std::move(o)) {
    // Derived specific
    ......
}

좋은 웹페이지 즐겨찾기