2016-09-21 11 views
1

나는 내가 관찰하고있는 것에 대한 이유를 모호하게 알고있을 것이라고 생각하지만, 확인이나 수정과 그에 대한 설명을 원합니다.rvalue를 반환 하시겠습니까? 또는 : 복사 생성자가`return <expression>`에 호출되는 이유는 무엇입니까?

나는 다음과 같은 코드가 있습니다

return (tmp <<= shift);

다른 : 나는 C<T>::operator<<(C<T>, unsigned)

차이의 두 가지 버전을

template <class T> 
class C 
{ 

public: 

    C() = default; 

    C(const C& rhs) : mem(rhs.mem) 
    { 
     std::cerr << "copy" << "\n"; 
    } 

    // does not call copy constructor twice 
    // friend C operator<<(C& src, unsigned shift) 
    // { 
    //  std::cerr << 1 << "\n"; 
    //  C tmp(src); 
    //  std::cerr << 2 << "\n"; 
    //  tmp <<= shift; 
    //  std::cerr << 5 << "\n"; 
    //  return tmp; 
    // } 

    // does call copy constructor twice 
    friend C operator<<(C& src, unsigned shift) 
    { 
     std::cerr << 1 << "\n"; 
     C tmp(src); 
     std::cerr << 2 << "\n"; 
     return (tmp <<= shift); 
    } 

    friend C& operator<<=(C& src, unsigned shift) 
    { 
     std::cerr << 3 << "\n"; 
     src.mem <<= shift; 
     std::cerr << 4 << "\n"; 
     return src; 
    } 

    T mem; 
}; 

int main() 
{ 
    C<int> c1; 

    c1 << 3; 
} 

이는 일이 식의 결과를 반환 변수를 반환합니다 :

return tmp

은 지금까지 나는 두 함수가 의미 상 동일 할 것이라고 생각하고 return a + 1int ret = a + 1; return ret보다 더 스타일이 될 것 같은 return (tmp <<= shift);을 가진 사람은 단순히 더 나은 스타일합니다. 이것은 분명히 그렇지 않으며 아마도 원자 데이터 유형에만 해당됩니다. return (tmp <<= shift);와 버전의 출력은 다음과 같습니다

1 
copy 
2 
3 
4 
copy 

이 같은 다른 출력 :

1 
copy 
2 
3 
4 
5 

는하지만, ITM에 <<=를 호출 한 후에 tmp을 반환하지 않습니다 return (tmp <<= shift); 그 권리를 가리키고 내 가정이다 <<=이 호출 된 후 tmp 사본으로 새 개체를 만드시겠습니까?

+0

복사 생성자가 호출 될 때 또는 테스트 할 경우 다른 최적화 수준으로 테스트해야합니다. 출력은 컴파일러, 컴파일러 최적화 등에 따라 완전히 다를 수 있습니다. – PaulMcKenzie

답변

1

값으로 돌아 오는 경우 반환 값을 초기화해야합니다. 반환 값은 C 유형의 객체입니다.

return (tmp <<= shift);의 경우 (tmp << shift)C의 초기화 자임을 의미합니다. 이 값은의 lvalue이므로 복사 구성입니다.

return identifier; 형태의 return 문에 대해서는 identifier이 lvalue 임에도 불구하고 move-construction이 될 수 있다는 특별한 규칙이 있습니다. 그러나이 규칙은 다른 표현식으로 확장되지 않습니다 (아직).

코드의 다른 버전은 특별한 규칙 활성화 수행합니다

여기 tmp
tmp <<= shift; 
return tmp; 

가 만드는를 rvalue로 간주 될 수 있습니다 그것을 이동 (그리고이 그것을 복사 생략 컨텍스트한다).

테스트에서 컴파일러는 복사 - 추출을 구현했습니다. 복사 - 추출없이 테스트하려면 (컴파일러가 사용자에게이를 허용하도록 설정하는 경우) C에 이동 생성자를 제공해야합니다. 사용자 제공 복사 생성자는 이동 생성자의 암시 적 생성을 억제합니다.

0

operator <<= 컴파일러 쉽게 반환 값 최적화을 사용하여 카피를 호출 할 필요가 결정할 수 있도록 상기 입력 매개 변수에 대한 참조를 반환 할 수있다 (아마도 다른 static/global 변수에 대한 참조를 반환한다) 건설자.

질문 : return (tmp <<= shift)을 쓸 때 컴파일러는 (tmp <<= shift)이 tmp에 대한 참조를 반환하는지 여부를 알지 못하지만, return tmp을 쓰면 컴파일러는이를 알고 최적화 할 수 있습니다.