i를 반환해야하는 경우 다음 코드 (func1 ())가 정확합니까? 지역 변수에 대한 참조를 반환 할 때 문제가 있다는 것을 읽은 것을 기억합니다. func2 ()와 어떻게 다릅니 까?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
i를 반환해야하는 경우 다음 코드 (func1 ())가 정확합니까? 지역 변수에 대한 참조를 반환 할 때 문제가 있다는 것을 읽은 것을 기억합니다. func2 ()와 어떻게 다릅니 까?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
답변:
이 코드 조각 :
int& func1()
{
int i;
i = 1;
return i;
}
수명이 함수 호출 범위로 제한된 객체에 대한 별칭 (참조)을 반환하므로 작동하지 않습니다. 즉 func1(), int i이제는 존재하지 않는 객체를 참조하기 때문에 함수에서 반환 된 참조를 쓸모 없게 만듭니다.
int main()
{
int& p = func1();
/* p is garbage */
}
두 번째 버전은 변수가 함수 호출의 수명에 제한되지 않는 무료 저장소에 할당되기 때문에 작동합니다. 그러나 delete할당 된 int.
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
일반적으로 포인터를 일부 RAII 클래스 및 / 또는 팩토리 함수로 래핑하여 delete직접 수행 할 필요가 없습니다 .
두 경우 모두 값 자체를 반환 할 수 있습니다 (제공 한 예제가 아마도 인위적 이었음을 알고 있습니다).
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
func3()오늘날 거의 모든 컴파일러가 어떤 형태의 반환 값 최적화를 구현하기 때문에 동일한 방식 으로 원시 값을 반환 하는 방식으로 큰 객체를 반환하는 것이 좋습니다 .
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
흥미롭게도 임시 참조를 const 참조에 바인딩하는 것은 완벽하게 합법적 인 C ++ 입니다.
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
int* p = func2(); delete p;지금 삭제하고 있습니다. 'p'를 삭제하면 함수 func2()정의 "내부"에 할당 된 메모리 도 삭제 되었음을 의미 합니까?
func2()되고 다음 줄에서 외부에서 해제되었습니다. 하지만 RAII의 일부 변형을 대신 사용하겠다고 말한 것처럼 메모리를 처리하는 다소 오류가 발생하기 쉬운 방법입니다. 그건 그렇고, 당신은 C ++를 배우는 것처럼 들립니다. 배울 수 있는 좋은 입문 C ++ 책 을 선택하는 것이 좋습니다 . 또한 질문이있는 경우 나중에 참조 할 수 있도록 언제든지 Stack Overflow에 질문을 게시 할 수 있습니다. 댓글은 완전히 새로운 질문을하기위한 것이 아닙니다.
로컬 변수는 스택의 메모리이며, 해당 메모리는 범위를 벗어날 때 자동으로 무효화되지 않습니다. 중첩 된 함수 (메모리의 스택에서 더 높음)에서이 메모리에 액세스하는 것이 완벽하게 안전합니다.
함수가 반환되고 종료되면 상황이 위험 해집니다. 일반적으로 돌아올 때 메모리는 삭제되거나 덮어 쓰여지지 않습니다. 이는 해당 주소의 메모리에 여전히 데이터가 포함되어 있음을 의미합니다. 포인터가 유효한 것처럼 보입니다.
다른 함수가 스택을 만들고 덮어 쓸 때까지. 이것이 한동안 작동 할 수있는 이유입니다. 특히 깊이 중첩 된 함수 세트 또는 정말 크기가 크거나 많은 로컬 객체가있는 함수가 해당 스택 메모리에 다시 도달하면 갑자기 작동이 중단됩니다.
동일한 프로그램 부분에 다시 도달하여 이전 지역 함수 변수를 새 함수 변수로 덮어 쓸 수도 있습니다. 이 모든 것은 매우 위험하며 극도로 낙담해야합니다. 로컬 개체에 대한 포인터를 사용하지 마십시오!
기억해야 할 점은 이러한 간단한 규칙이며 매개 변수와 반환 유형 모두에 적용됩니다.
각각에 대한 시간과 장소가 있으므로 그들을 알고 있는지 확인하십시오. 여기에 표시된대로 지역 변수는 함수 범위에서 지역적으로 살아있는 시간으로 제한됩니다. 귀하의 예에서 반환 유형 int*과 반환 &i은 똑같이 잘못되었을 것입니다. 이 경우에는 더 나을 것입니다 ...
void func1(int& oValue)
{
oValue = 1;
}
이렇게하면 전달 된 매개 변수의 값이 직접 변경됩니다. 이 코드는 ...
void func1(int oValue)
{
oValue = 1;
}
하지 않을 것입니다. oValue함수 호출에 대한 로컬 값을 변경합니다 . 그 이유는 실제로 자체가 oValue아닌 의 "로컬"복사본 만 변경하기 때문 oValue입니다.
int& i = * new int;