질문 : C ++ 프로그래머가 'new'사용을 최소화해야하는 이유는 무엇입니까?
std :: list <std :: string>을 사용할 때 std :: string 으로 스택 오버플로 질문 메모리 누수를 우연히 발견 했으며 주석 중 하나는 다음 과 같이 말합니다.
사용을 중지 new
너무 많이. 당신이 한 곳에서 새로운 것을 사용한 이유를 볼 수 없습니다. C ++ 에서 값별로 객체를 생성 할 수 있으며 이는 언어 사용의 큰 장점 중 하나입니다.
힙에 모든 것을 할당 할 필요는 없습니다.
자바 프로그래머처럼 생각하지 마세요.
그게 무슨 뜻인지 잘 모르겠습니다.
왜 객체는 가능한 한 자주 C ++의 값으로 생성되어야하며 내부적으로 어떤 차이가 있습니까?
내가 답을 잘못 해석 했습니까?
답변
널리 사용되는 메모리 할당 기술에는 자동 할당과 동적 할당의 두 가지가 있습니다. 일반적으로 스택과 힙 각각에 해당하는 메모리 영역이 있습니다.
스택은 항상 순차적 인 방식으로 메모리를 할당합니다. 역순 (First-In, Last-Out : FILO)으로 메모리를 해제해야하기 때문에 그렇게 할 수 있습니다. 이것은 많은 프로그래밍 언어에서 지역 변수에 대한 메모리 할당 기술입니다. 최소한의 부기가 필요하고 할당 할 다음 주소가 암시 적이기 때문에 매우 빠릅니다.
C ++에서는 스토리지가 범위 끝에서 자동으로 청구되기 때문에 이를 자동 스토리지라고합니다. 현재 코드 블록 ( {}
구분)의 실행이 완료되면 해당 블록의 모든 변수에 대한 메모리가 자동으로 수집됩니다. 이것은 또한 리소스를 정리하기 위해 소멸자가 호출되는 순간입니다.
힙은보다 유연한 메모리 할당 모드를 허용합니다. 부기가 더 복잡하고 할당이 느립니다. delete
또는 delete[]
(C에서는 free
를 사용하여 메모리를 수동으로 해제해야합니다. 그러나 암시 적 릴리스 지점이 없다는 것이 힙 유연성의 핵심입니다.
힙을 사용하는 것이 더 느리고 잠재적으로 메모리 누수 또는 메모리 조각화로 이어 지더라도 덜 제한적이므로 동적 할당에 대한 완벽한 사용 사례가 있습니다.
동적 할당을 사용하는 두 가지 주요 이유 :
- 컴파일 타임에 얼마나 많은 메모리가 필요한지 모릅니다. 예를 들어, 텍스트 파일을 문자열로 읽을 때 일반적으로 파일의 크기를 알지 못하므로 프로그램을 실행할 때까지 할당 할 메모리 양을 결정할 수 없습니다.
- 현재 블록을 떠난 후에도 지속될 메모리를 할당하려고합니다. 예를 들어, 파일의 내용을 반환
string readfile(string path)
이 경우 스택이 전체 파일 내용을 보유 할 수 있더라도 함수에서 돌아와 할당 된 메모리 블록을 유지할 수 없습니다.
C ++에는 소멸 자라는 깔끔한 구조가 있습니다. 이 메커니즘을 사용하면 리소스의 수명을 변수의 수명에 맞춰 리소스를 관리 할 수 있습니다. 이 기술을 RAII 라고하며 C ++의 특징입니다. 자원을 객체로 "랩"합니다. std::string
은 완벽한 예입니다. 이 스 니펫 :
int main ( int argc, char* argv[] )
{
std::string program(argv[0]);
}
실제로 가변적 인 양의 메모리를 할당합니다. std::string
객체는 힙을 사용하여 메모리를 할당하고 소멸자에서 해제합니다. 이 경우 리소스를 수동으로 관리 할 필요가 없었고 동적 메모리 할당의 이점을 계속 얻었습니다.
특히이 스 니펫에서 다음을 의미합니다.
int main ( int argc, char* argv[] )
{
std::string * program = new std::string(argv[0]); // Bad!
delete program;
}
불필요한 동적 메모리 할당이 있습니다. 이 프로그램은 더 많은 타이핑 (!)을 필요로하며 메모리 할당 해제를 잊어 버릴 위험이 있습니다. 명백한 이점없이이를 수행합니다.
기본적으로 마지막 단락에서 요약합니다. 가능한 자주 자동 저장을 사용하면 프로그램이 다음과 같이됩니다.
- 입력이 더 빠릅니다.
- 달리면 더 빠릅니다.
- 메모리 / 리소스 누수가 덜 발생합니다.
참조 된 질문에는 추가 문제가 있습니다. 특히 다음 클래스 :
class Line {
public:
Line();
~Line();
std::string* mString;
};
Line::Line() {
mString = new std::string("foo_bar");
}
Line::~Line() {
delete mString;
}
실제로 다음 중 사용하는 것보다 훨씬 더 위험합니다.
class Line {
public:
Line();
std::string mString;
};
Line::Line() {
mString = "foo_bar";
// note: there is a cleaner way to write this.
}
그 이유는 std::string
이 복사 생성자를 올바르게 정의하기 때문입니다. 다음 프로그램을 고려하십시오.
int main ()
{
Line l1;
Line l2 = l1;
}
원래 버전을 사용하면이 프로그램은 동일한 문자열에서 delete
수정 된 버전을 사용하면 각 Line
인스턴스는 자체 메모리를 가진 자체 문자열 인스턴스를 소유하고 둘 다 프로그램이 끝날 때 해제됩니다.
RAII의 광범위한 사용은 위의 모든 이유 때문에 C ++에서 모범 사례로 간주됩니다. 그러나 즉시 명확하지 않은 추가 이점이 있습니다. 기본적으로 부품의 합보다 낫습니다. 전체 메커니즘 은 . 확장됩니다.
Line
클래스를 빌딩 블록으로 사용하는 경우 :
class Table
{
Line borders[4];
};
그때
int main ()
{
Table table;
}
4 개의 std::string
인스턴스, 4 개의 Line
인스턴스, 1 개의 Table
인스턴스 및 모든 문자열의 내용을 할당하면 모든 것이 자동으로 해제 됩니다.
출처 : https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new
'프로그래밍 언어 > C++' 카테고리의 다른 글
C ++ 컴파일이 오래 걸리는 이유 (0) | 2021.07.23 |
---|---|
Collatz 추측을 테스트하기위한 C ++ 코드가 손으로 작성한 어셈블리보다 빠르게 실행되는 이유 (0) | 2021.07.23 |
확실한 C ++ 의 가이드 및 목록 (0) | 2021.07.23 |
C 및 C ++에서 char를 int로 변환 (0) | 2021.07.23 |
C ++에서 PI 상수를 사용하는 방법 (0) | 2021.07.22 |