프로그래밍 언어/C++

C ++ 프로그래머가 'new'사용을 최소화해야하는 이유

Rateye 2021. 7. 23. 11:16
728x90
반응형

 

질문 : 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
728x90
반응형