2012-12-06 4 views
0

의 값인 및 lvalue에 대해 몇 시간을 보냈습니다. 여기에 내가C++ 03의 반환 값

int main() 
{ 
    //..... 
    Foo foo = Bar1(); 
    foo = Bar2(); 
    //...... 
} 

Foo Bar1() 
{ 
    //Do something including create foo 
    return foo; 
} 

Foo& Bar2() 
{ 
    //Do something including create foo 
    return foo; 
} 

는 C++ 03에서 Bar1()가 (단지 반환 전) 반환 객체를 복사 한 다음 복사 된 객체의 주소를 반환 이해하는 것입니다; 파괴 될 개체의 낭비적인 복사본을 실행합니다. Bar2()은 함수 내에서 생성 된 객체를 반환합니다.

C++ 11에서, Bar1()Bar2()은 본질적으로 동일합니다 (또한 C++ 03의 Bar2()과 동일).

맞습니까? 그렇지 않다면 자세히 설명하십시오.

+0

나는 당신의 질문에 대답했지만, 나는 당신의 코드가 의미하는 것으로 실제로 혼란 스럽다. 'Bar1' /'Bar2'는 앞에서 선언 한'Foo' 타입의 전역 값을 어떻게 든 리턴합니까? 그런데'Foo foo = Bar1()'이 부정확 할 것입니다 ... – CygnusX1

+1

각 함수의 시작 부분에 (적어도)'Foo foo;'를 추가하고'a'와'b' 바깥에 변수의 이름을 지정하십시오 (왜냐하면 'Foo foo'를 두 번 정의 할 수 없음) – leemes

+3

코드를 명확하게해야합니다. 이 시점에서 그것은 완전히 엉망이며, 질문은 완전히 무의미합니다. 'Foo foo'를 두 번 정의하는 것은 불법입니다. 또한'foo'는 위에서 선언 한'foo'와 같은 함수에서 리턴됩니까? (즉, 객체 자체를 초기화하려고합니까?) – AnT

답변

1

rvalues ​​및 lvalues의 개념은 이전 C++에서 C++ 11로 변경되지 않았습니다. "C++ 03"로 설명하는 것은 일어날 일입니다. 일부 컴파일러 최적화는 불필요한 복사 생성자 호출을 포함하여 불필요한 사본의 수를 줄일 수 있지만 그렇지 않은 경우에는 동일합니다.

C++ 11에서는 rvalue-reference (T&&)의 개념이 도입되었습니다.

당신이 여기에 예를 들어, 최대 구글 수 거기에 몇 가지 기사가 있습니다

http://thbecker.net/articles/rvalue_references/section_01.html

6

이들은 동일하지 않습니다. Bar2()은 두 표준 모두에 의해 UB입니다. 참조로 스택에 생성 된 객체를 반환 할 수 없습니다.

C++에서 03 Bar1()은 RVO를 이용할 수 있으며 아무 것도 복사되지 않습니다. C++ 11에서는 Bar1()도 RVO를 사용하거나 RVO를 사용할 수없는 경우 이동 생성자를 사용합니다.

+0

왜'Bar2()'가 정의되지 않았습니까? 반환 된 개체의 전역 범위가있는 것 같습니다. 사실, 각 함수에 있어야하지만 질문에서는 생략 된 로컬 foo가있을 것입니다. 어떤 경우에는'Bar2()'는 실제로 정의되지 않은 동작을합니다. –

+1

해당 코드에서 "스택에 생성 된 개체"는 어디에서 볼 수 있습니까? – AnT

+1

@AndreyT : 전 세계적으로'foo' 객체가 보이지 않습니다. 두 개의 동일한'foo' 변수가 있으므로 코드의 다른 부분으로 의심됩니다. 또한 Bar2()는'foo'를 초기화하는 데 사용되므로 라인이 관련이 없다는 또 다른 단서입니다. –

0

BAR2() 함수 내에서 생성 된 객체를 반환합니다.

분명히 잘못되었습니다. Bar2()은 어떤 개체에 참조을 반환합니다. (주 : 객체가 스택 안의 Bar2() 내부에 생성되면 UB가됩니다).

C++ 11에서 Bar1()과 Bar2()는 본질적으로 동일합니다 (또한 C++ 03의 Bar2()와 등가 임).

C++ 11에서의 의미는 같습니다.

Foo Bar3() 
{ 
    //Do something 
    return std::move(foo); 
} 

이 복사 생성자를 실행하지,하지만 이동 생성자 - 더 적은 자원을 배가해야한다 : 당신이 정말 관심은 이동의 의미입니다.

0

이 문서에 대한 흥미로운 일이 될 수 있습니다 : C++ 03, Bar1() 개체를 복사 할 수 있습니다 (그러나 이것은 소위 복사 생략에 멀리 최적화 - 링크 참조) Want Speed? Pass by Value.

에서.

C++ 11에서는 기본적으로 아무 것도 변경되지 않았습니다.컴파일러는 Foo의 복사 생성자 또는 Foo의 이동 생성자를 호출하거나 elision을 복사 할 수 있습니다. 그러나 C++ 03에서도 복사가 생략되므로 Bar1()은 C++ 11 및 C++ 03에서 동일한 작업을 수행합니다.

Bar2() 반환 값은 C++ 11과 다르지 않습니다. 참조를 반환하는 것이 중요 할 수 있습니다. foo이 로컬 값이면 이미 파괴 된 변수에 대한 참조가 반환되며 절대 반환되지 않습니다.

1

Bar2()은 어떤 사본을 만들지 않습니다 중 하나를 C++ 2003 또는 Bar1()foo의 복사본이 생성됩니다를 들어 C++ 2011 모두 C++ 2003 및 C++ 2011이를 rvalue 참조의 사용은 당신이 실제로를 rvalue를 할 때 또는 적용 만약 당신이 왼쪽으로 돌아가려는 좌변가를 가지고 있다면 그것은 돌려 주어집니다.

물론 foo이 반환되는 것은 초기화되는 foo이기 때문에 예제는 정의되지 않은 동작입니다. 다시 말하면, foo이 무엇을 의미하는지 알려주지 않으면 예제가 엉망이되는 것 같습니다. 각각의 기능을 가정하면 지역 변수 foo을 가지고, Bar2()은 정의되지 않은 동작은 모두 표준에 따라이며 Bar1() 다소 다르다 : C++ 2003 사용할 수있는 반면

  • Foo의 이동 생성자가있는 경우, ++ 2011 C는 이동 생성자를 사용할 수있다 카피 생성자.
  • 이동 생성자 또는 복사 생성자 중 하나가 사용되는지 여부는 나머지 함수 및 컴파일러에 따라 다릅니다. Bar1()에있는 모든 return 문이 대부분 foo을 반환하면 대부분의 컴파일러에서 여분의 객체 생성이 생략됩니다.
+0

"* Bar1()에 대해 foo의 복사본이 C++ 2003과 C++ 2011 모두에 만들어집니다. *"완전히 사실이 아닙니다. 그것은'foo' 정의 방법에 달려 있습니다. 스택 변수이면 생략되거나 이동됩니다. 복사가 발생하면 이동이 불가능하기 때문입니다. –

+0

@NicolBolas : 원래 예제는 실제로 복사 될 전역 변수'foo'를 가진 것처럼 보였습니다. 그 이후로 질문을 편집하여 이것을 없애고, 실제로 foo가 어떻게 선언되었는지에 달려있다. –