[c++] C ++에서 언제 새 키워드를 사용해야합니까?

나는 잠시 동안 C ++을 사용하고 있으며 새로운 키워드 에 대해 궁금해하고 있습니다. 간단히 말해서 사용해야합니까?

1) 새로운 키워드로 …

MyClass* myClass = new MyClass();
myClass->MyField = "Hello world!";

2) 키워드가 없으면 …

MyClass myClass;
myClass.MyField = "Hello world!";

구현의 관점에서, 그들은 다른 것처럼 보이지는 않지만 (그러나 나는 그들이 확실합니다) … 그러나, 나의 주요 언어는 C #이며, 물론 첫 번째 방법은 내가 익숙한 것입니다.

어려움 1은 방법 1이 std C ++ 클래스와 함께 사용하기 어렵다는 것 같습니다.

어떤 방법을 사용해야합니까?

업데이트 1 :

나는 최근 에 범위를 벗어난 (즉 함수에서 반환되는) 큰 배열 에 메모리 (또는 free store )에 새로운 키워드를 사용했습니다 . 스택을 사용하기 전에 요소의 절반이 범위 밖에서 손상되어 힙 사용으로 전환하면 요소가 제대로 유지되었습니다. 예이!

업데이트 2 :

내 친구가 최근에 new키워드 를 사용하는 간단한 규칙이 있다고 말했습니다 . 입력 할 때마다을 new입력하십시오 delete.

Foobar *foobar = new Foobar();
delete foobar; // TODO: Move this to the right place.

이렇게하면 삭제를 항상 어딘가에 배치해야하므로 (예를 들어 잘라서 소멸자 또는 다른 방식으로 붙여 넣을 때) 메모리 누수를 방지 할 수 있습니다.



답변

방법 1 (사용 new )

  • 사용 가능한 저장소 의 오브젝트에 메모리를 할당합니다 (이것은 종종 과 동일합니다 )
  • delete나중에 개체 를 명시 적으로 지정 해야합니다. (삭제하지 않으면 메모리 누수가 발생할 수 있습니다)
  • 메모리는 할당 될 때까지 할당 된 상태를 유지 delete합니다. (즉,을 return사용하여 만든 객체 일 수 있음 new)
  • 포인터가 d 가 아니면 문제의 예에서 메모리누출됩니다delete . 그것은 항상 삭제해야 관계없이 수행되는 제어 경로, 또는 예외가 발생하는 경우.

방법 2 (사용하지 않음 new)

  • 스택 에 객체에 대한 메모리 할당 (모든 로컬 변수가있는 경우) 일반적으로 스택에 사용 가능한 메모리가 적습니다. 너무 많은 객체를 할당하면 스택 오버플로가 발생할 위험이 있습니다.
  • delete나중에 필요하지 않습니다 .
  • 메모리가 범위를 벗어나면 더 이상 할당되지 않습니다. (즉 return, 스택의 객체에 대한 포인터 가 아니어야 함 )

어느 것을 사용해야하는지; 위의 제약 조건에 따라 가장 적합한 방법을 선택하십시오.

몇 가지 쉬운 경우 :

  • 호출 delete(및 메모리 누수 의 가능성)에 대해 걱정하지 않으려면 사용하지 않아야합니다 new.
  • 함수에서 객체에 대한 포인터를 반환하려면 new

답변

둘 사이에는 중요한 차이점이 있습니다.

모든 것은 할당하지 new많은 C #에서 값 유형처럼 동작합니다 (그리고 사람들은 그 객체가 아마도 가장 일반적인 / 명백한 경우입니다 스택에 할당 된, 그러나 항상 진실 것을 말한다. 더 정확하게, 할당 된 개체 사용하지 않고 new있는 자동 스토리지를 duration
할당 된 모든 것이 new힙에 할당되고 C #의 참조 유형과 정확히 동일하게 이에 대한 포인터가 반환됩니다.

스택에 할당 된 것은 컴파일 타임에 결정 된 일정한 크기를 가져야합니다 (컴파일러는 스택 포인터를 올바르게 설정해야하거나 객체가 다른 클래스의 멤버 인 경우 다른 클래스의 크기를 조정해야합니다) . 이것이 C #의 배열이 참조 유형 인 이유입니다. 참조 유형을 사용하면 런타임에 요청해야 할 메모리 양을 결정할 수 있기 때문입니다. 그리고 여기에도 동일하게 적용됩니다. 일정한 크기 (컴파일 타임에 결정될 수있는 크기)를 가진 어레이 만 자동 스토리지 기간 (스택에서)으로 할당 될 수 있습니다. 동적 크기 배열은 다음을 호출하여 힙에 할당해야합니다.new .

(그리고 C #과의 유사성이 멈추는 곳)

이제 스택에 할당 된 모든 항목에 “자동”저장 기간이 있습니다 (실제로 변수를 auto 있지만 다른 저장 유형이 지정되지 않은 경우 기본값으로 사용되므로 키워드가 실제로 사용되지는 않습니다). 에서 오는)

자동 저장 기간은 정확히 소리가 나는 것을 의미하며 변수의 기간은 자동으로 처리됩니다. 반대로 힙에 할당 된 항목은 수동으로 삭제해야합니다. 예를 들면 다음과 같습니다.

void foo() {
  bar b;
  bar* b2 = new bar();
}

이 함수는 고려할 가치가있는 세 가지 값을 만듭니다.

1 행 에서 스택 b에 유형 변수 를 선언합니다 bar(자동 지속 시간).

라인 2 일, 그것은 선언 bar포인터 b2스택 (자동 지속 시간)에를, 그리고 새로운 할당를 호출bar 힙에 객체를. (동적 지속 시간)

함수가 반환되면 다음이 발생합니다. 첫째, b2범위를 벗어납니다 (파괴 순서는 항상 구성 순서와 반대 임). 그러나 b2포인터 일뿐이므로 아무 일도 일어나지 않으며 차지하는 메모리가 단순히 해제됩니다. 그리고 중요한 것은 그것이 가리키는 메모리 ( bar힙 의 인스턴스)는 건드리지 않는다는 것입니다. 포인터 만 자동 지속 시간을 가지므로 포인터 만 해제됩니다. 둘째, b범위를 벗어나므로 자동 지속 시간이 있으므로 소멸자가 호출되고 메모리가 해제됩니다.

그리고 bar 더미에 인스턴스? 아마 여전히 거기에 있습니다. 아무도 그것을 귀찮게하지 않았으므로 메모리가 누출되었습니다.

이 예제에서 우리는 자동 지속 시간을 가진 모든 것이 범위를 벗어날 때 소멸자가 호출되도록 보장 합니다. 유용합니다. 그러나 힙에 할당 된 것은 필요한만큼 지속되며 배열의 경우와 같이 동적으로 크기를 조정할 수 있습니다. 또한 유용합니다. 이를 사용하여 메모리 할당을 관리 할 수 ​​있습니다. Foo 클래스가 생성자의 힙에 일부 메모리를 할당하고 소멸자에서 해당 메모리를 삭제하면 어떻게 될까요? 그런 다음 다시 확보 할 수있는 안전한 메모리 할당을 보장 할 수 있지만 모든 것을 스택에 강제로 저장하는 데 제한이 없습니다.

이것이 대부분의 C ++ 코드 작동 방식과 거의 같습니다. std::vector예를 들어 표준 라이브러리를보십시오 . 일반적으로 스택에 할당되지만 동적으로 크기를 조정하고 크기를 조정할 수 있습니다. 그리고 필요에 따라 힙에 메모리를 내부적으로 할당하여이를 수행합니다. 클래스의 사용자는 이것을 보지 못하므로 메모리가 누출되거나 할당 한 것을 정리하는 것을 잊을 수 없습니다.

이 원칙을 RAII (Resource Acquisition is Initialization)라고하며 획득 및 해제해야하는 모든 리소스로 확장 할 수 있습니다. (네트워크 소켓, 파일, 데이터베이스 연결, 동기화 잠금). 모든 생성자는 생성자에서 획득하고 소멸자에서 해제 할 수 있으므로 획득 한 모든 자원이 다시 해제됩니다.

일반적으로 상위 수준 코드에서 직접 새로 만들기 / 삭제를 사용하지 마십시오. 항상 메모리를 관리 할 수있는 클래스로 랩핑하여 메모리가 다시 해제되도록하십시오. (예,이 규칙에는 예외가있을 수 있습니다. 특히, 스마트 포인터를 사용하려면 new직접 호출 하고 포인터를 생성자에게 전달해야합니다. 그러면 포인터가 생성자를 delete제대로 수행하고 올바르게 호출됩니다. 그러나 여전히 매우 중요한 규칙입니다. )


답변

어떤 방법을 사용해야합니까?

이것은 타이핑 환경 설정에 따라 결정되는 것이 아니라 컨텍스트에 따라 결정됩니다. 객체를 몇 개의 스택에 유지해야하거나 스택에 비해 너무 무거 우면 무료 저장소에 할당하십시오. 또한 개체를 할당하기 때문에 메모리를 해제해야합니다. 조회delete운영자를 .

자유 매장 관리 사람들 사용의 부담을 완화하기 위해 같은 물건을 발명 한 auto_ptrunique_ptr. 이것들을 살펴 보는 것이 좋습니다. 입력 문제에 도움이 될 수도 있습니다. 😉


답변

C ++로 작성하는 경우 성능을 위해 작성 중일 수 있습니다. 새로운 저장소와 무료 저장소를 사용하면 스택을 사용하는 것보다 (특히 스레드를 사용할 때) 속도가 훨씬 느리므로 필요할 때만 사용하십시오.

다른 사람들이 말했듯이 객체가 함수 또는 객체 범위 외부에 있어야 할 때, 객체가 실제로 크거나 컴파일 타임에 배열의 크기를 모르는 경우 새 것이 필요합니다.

또한 삭제를 사용하지 마십시오. 대신 새로운 것을 스마트 포인터로 감싸십시오. 스마트 포인터 호출을 통해 삭제하십시오.

스마트 포인터가 똑똑하지 않은 경우가 있습니다. STL 컨테이너 안에 std :: auto_ptr <>을 저장하지 마십시오. 컨테이너 내부의 복사 작업으로 인해 포인터가 너무 빨리 삭제됩니다. 또 다른 경우는 객체에 대한 포인터의 STL 컨테이너가 실제로 큰 경우입니다. boost :: shared_ptr <>은 참조 카운트를 올리거나 내릴 때 엄청난 속도 오버 헤드를 갖습니다. 이 경우 더 좋은 방법은 STL 컨테이너를 다른 객체에 넣고 해당 객체에 컨테이너의 모든 포인터에서 delete를 호출하는 소멸자를 제공하는 것입니다.


답변

짧은 대답은 : 당신이 C ++에서 초보자라면, 당신이해야 결코 사용되지 newdelete자신.

대신 std::unique_ptrand std::make_unique(또는 덜 자주 std::shared_ptrstd::make_shared) 와 같은 스마트 포인터를 사용해야합니다 . 그렇게하면 메모리 누수에 대해 거의 걱정할 필요가 없습니다. 당신이 더 진보 된 경우에도 그리고, 가장 좋은 방법은 일반적으로 사용하고있는 사용자 정의 방식을 캡슐화하는 것 newdelete 단지 객체의 라이프 사이클 문제에 전념하고 있습니다 (예 : 사용자 정의 스마트 포인터로) 작은 클래스로합니다.

물론 배후에서 이러한 스마트 포인터는 여전히 동적 할당 및 할당 해제를 수행하므로이를 사용하는 코드에는 여전히 관련 런타임 오버 헤드가 있습니다. 여기에있는 다른 답변은 이러한 문제와 스마트 포인터를 사용하는 시점과 스택에서 객체를 만들거나 객체를 직접 멤버로 통합하는 것과 비교할 때 디자인 결정을 내리는 방법에 대해 설명하지 않았습니다. 그러나 내 간부 요약은 무언가 강요 될 때까지 스마트 포인터 또는 동적 할당을 사용하지 마십시오.


답변

new키워드가 없으면 호출 스택 에 키워드를 저장합니다 . 스택에 너무 큰 변수를 저장하면 스택 오버플로가 발생 합니다.


답변

간단한 대답은 예입니다-new ()는 힙에 객체를 생성합니다 (불명 한 부작용으로 명시 적으로 delete를 호출하여 수명을 관리해야 함). 두 번째 양식은 현재 스택의 객체를 생성합니다 범위와 해당 개체가 범위를 벗어나면 소멸됩니다.