2010-02-19 8 views
14

다음 코드는 1, 2, 3을 인쇄합니다. 그것은 모든 C++ 컴파일러가 원했던 것과 사실입니까?왜 명명되지 않은 C++ 객체가 범위 블록이 끝나기 전에 파괴됩니까?


class Foo 
{ 
     const char* m_name; 
public: 
     Foo(const char* name) : m_name(name) {} 
     ~Foo() { printf("%s\n", m_name); } 
}; 

void main() 
{ 
     Foo foo("three"); 
     Foo("one"); // un-named object 
     printf("two\n"); 
} 
+0

복제본 : http://stackoverflow.com/questions/1388685/local-variable-scope-question –

답변

33

임시 변수는 작성된 전체 표현식의 끝까지 유지되며 세미콜론 (;)으로 끝납니다.

이 12.2/3이다

임시 개체는 전체 식 (1.9) 즉 (어휘)은 생성 된 시점을 포함 평가의 마지막 단계에서 파괴된다.

귀하의 행동은 보장됩니다.

만난 경우 임시의 수명을 연장 할 수있는 두 가지 조건이 있습니다. 첫 번째는 객체에 대한 이니셜 라이저입니다. 두 번째는 참조가 임시로 바인딩되는 경우입니다.

+3

... uless 임시의 수명을 연장 할 수있는 12.2/4의 조건이 충족됩니다. – AnT

+0

@ 안드레이 T : 어, 네. 언급하는 것이 중요 할 수도 있습니다. – GManNickG

+1

원래 질문의 맥락에서 언급하는 것이 중요하지 않을 수도 있습니다. 그러나 "표현식이 끝나면 임시 변수의 수명이 다되었습니다"라는 명시적인 주장을 읽은 후에는 언급 할만한 가치가 있다고 생각했습니다. – AnT

6

그런 임시 개체의 범위는 단 한 줄입니다. 생각해 보면 선이 끝난 후에 더 이상 참조 할 수 없으므로 객체가 주변에 머물러있는 이유는 무엇입니까?

그렇지 않은 경우 컴파일러는 함수 호출에서 임시 개체를 최적화 할 수 없습니다.

3

네, 그렇습니다.

Foo foo("three")은 범위가 끝날 때 파괴 될 정상적인 개체를 만듭니다.

Foo("one")은 명령어 [1]의 끝 부분에서 삭제되는 임시 객체를 만듭니다. 왜? 명령이 끝나면 액세스 할 수있는 방법이 없기 때문입니다.

[1] 고의적 단순화 : 시퀀스 포인트을 말 했어야합니다.

+9

시퀀스 포인트와 관련이 없습니다. 임시 객체의 수명은 객체를 생성 한 "명령"의 끝 부분에 시퀀스 포인트가 있더라도 전체 표현식의 끝에서 끝납니다. 예를 들어, 'Foo ("a"), Foo ("b"), Foo ("c"); 모든 세 가지 임시 변수는 중간에 순서 점이 있더라도 명령문의 끝까지 살아있게 보장됩니다 . – AnT

11

임시 개체의 수명을 제어하는 ​​규칙은 범위의 개념과 아무 관련이 없습니다. 범위는 의 이름이고이며 임시 개체에는 이름이 없습니다. 즉, 임시 객체에는 범위가 없습니다.

대부분의 경우 임시 객체의 수명은 해당 객체를 만든 전체 표현식의 끝에서 끝나며 이는 실험에서 관찰 한 것입니다. 이것은 몇 가지 예외가있는 일반적인 규칙입니다. 메인 하나는 즉시 임시 개체에 대한 참조를 부착하는 경우, 개체의 수명이 오래 rfoo 같은 삶을 살 것이다 참조

const Foo &rfoo = Foo("one"); 

위의 일시의 수명에 맞게 확장 될 것입니다.

+0

+1'범위는 이름의 속성이고, 임시 객체는 이름을 갖지 않습니다. '임시의 수명은'const '한정자가있는 참조로의 바인딩을 확장합니까? 'Foo & rfoo = Foo ("one");' – Mahesh

+0

임시의 생명 시간은'const' 참조에 대해서만 확장 될 수 있다고 읽었습니다. 그러나 예제 http://ideone.com/nTVPZ는 VS 2010에서는 잘 작동하지만 gcc에서는 작동하지 않습니다. (두 경우 모두 'this'는 주어진 링크에서 동일하며 'const'한정자 없이도 임시로 수명 연장을 의미합니다 VS에서). gcc 또는 VS가 올바른가? – Mahesh

+0

@Mahesh :이 코드는 표준 C++에서 컴파일 할 수 없으므로 GCC가이를 거부합니다. VS는 확장 기능을 사용하도록 설정했기 때문에 확장 기능으로 만 사용합니다. VS에서 언어 확장을 사용하지 않으면 VS에서도 코드가 컴파일되지 않습니다. – AnT

0

표준위원회가 잘못되어 있기 때문입니다. 그들이 그것을하기로 결정했기 때문에 그것을합니다. 이 방법으로 정의됩니다. 이름이 지정된 것과 동일한 범위의 익명 인스턴스로 간주되어야합니다. 인스턴스화 시점에서 블록의 끝까지. 분명히 그들은 임시 함수를 스택에 밀어 넣고 함수 호출이 끝날 때 스택에서 튀어 나오는 함수에 임시 함수를 전달하는 것이 유일한 용도라고 생각했습니다.

명명되지 않은 개체는 여전히 스택에 푸시되어야하며 블록이 끝날 때까지 스택에 남아 있어야합니다. 따라서 스택이 예상대로 스택에서 튀어 나오게됩니다. 단일 명령문에서 오브젝트를 작성하고 소멸시키는 것은 의미가 없습니다. 이 인스턴스가 실제로 유용한 단일 인스턴스/사례를보고 싶습니다. 블록의 지속 기간 동안 범위에 머물러 있지 않으면 가장 확실하게 오류가 발생하며 최소한 경고를 생성해야합니다.

+1

스택을 명시 적으로 말하는 것은 불필요합니다. 스택을 전혀 사용하지 않고 정적 위치에 모든 것을 할당하는 유용한 C++ 구현을 갖는 것이 완벽하게 가능합니다. 작은 임시 값이 주소 지정 가능 메모리가 아닌 레지스터에서 전달 될 수도 있습니다. –

+1

"단일 문장에서 개체를 생성하고 소멸시키는 것은 의미가 없습니다." 부작용이나 전환 사슬에서 그렇게하는 것은 아닙니다. 파이어 폭스와 같은 주요 C++ 프로젝트는 수천 개의 이러한 구조가 유용 할 수 있습니다. 그들은 대단히 유용합니다. 이러한 객체가 블록 끝까지 유지된다면 전체 메모리 사용량이 크게 변경되지 않더라도 캐시 압력은 많은 프로젝트의 성능을 저하시킵니다. –

관련 문제