답변:
반대로, 경험상 사용자 코드에 새 / 삭제가 없어야하는 한 항상 스택 할당을 선호해야합니다.
말했듯이, 변수가 스택에서 선언되면 해당 소멸자가 범위를 벗어날 때 자동으로 호출되며, 이는 리소스 수명을 추적하고 누수를 방지하기위한 주요 도구입니다.
따라서 일반적으로 메모리 (new 호출), 파일 핸들, 소켓 또는 기타 모든 리소스를 할당해야 할 때마다 생성자가 리소스를 획득하고 소멸자가이를 해제하는 클래스로 래핑합니다. 그런 다음 스택에 해당 유형의 개체를 만들 수 있으며 리소스가 범위를 벗어날 때 리소스가 해제되도록 보장됩니다. 이렇게하면 메모리 누수를 방지하기 위해 모든 곳에서 새 / 삭제 쌍을 추적 할 필요가 없습니다.
이 관용구의 가장 일반적인 이름은 RAII입니다.
또한 전용 RAII 개체 외부에 새로운 항목을 할당해야하는 드문 경우에 결과 포인터를 래핑하는 데 사용되는 스마트 포인터 클래스를 살펴보십시오. 대신 포인터를 스마트 포인터에 전달하면, 예를 들어 참조 카운트를 통해 수명을 추적하고 마지막 참조가 범위를 벗어날 때 소멸자를 호출합니다. 표준 라이브러리는 std::unique_ptr
단순한 범위 기반 관리를 위해 있으며 std::shared_ptr
공유 소유권을 구현하기 위해 참조 계산을 수행합니다.
많은 튜토리얼은 다음과 같은 스 니펫을 사용하여 객체 인스턴스화를 보여줍니다.
그래서 당신이 발견 한 것은 대부분의 튜토리얼이 형편 없다는 것입니다. ;) 대부분의 튜토리얼은 필요하지 않을 때 변수를 생성하기 위해 new / delete를 호출하고 할당 수명을 추적하는 데 어려움을주는 것을 포함하여 형편없는 C ++ 사례를 가르칩니다.
스택에있는 것이 할당 및 자동 해제 측면에서 이점이 될 수 있지만 몇 가지 단점이 있습니다.
스택에 거대한 개체를 할당하고 싶지 않을 수 있습니다.
다이나믹 파견! 이 코드를 고려하십시오.
#include <iostream>
class A {
public:
virtual void f();
virtual ~A() {}
};
class B : public A {
public:
virtual void f();
};
void A::f() {cout << "A";}
void B::f() {cout << "B";}
int main(void) {
A *a = new B();
a->f();
delete a;
return 0;
}
그러면 "B"가 인쇄됩니다. 이제 Stack을 사용할 때 어떤 일이 발생하는지 살펴 보겠습니다.
int main(void) {
A a = B();
a.f();
return 0;
}
이렇게하면 "A"가 인쇄되며 Java 또는 기타 객체 지향 언어에 익숙한 사용자에게는 직관적이지 않을 수 있습니다. 그 이유는 B
더 이상 인스턴스에 대한 포인터가 없기 때문입니다 . 대신의 인스턴스 B
가 생성되고 a
유형의 변수에 복사됩니다 A
.
특히 C ++를 처음 접할 때 어떤 일이 직관적이지 않게 발생할 수 있습니다. C에서는 포인터가 있고 그게 전부입니다. 당신은 그것들을 사용하는 방법을 알고 있으며 그들은 항상 동일합니다. C ++에서는 그렇지 않습니다. 그냥 당신이하는 방법에 대한 인수로이 예에서 사용할 때, 무슨 상상 - 일을 더 복잡하게 얻을 경우는 큰 차이를 만들 않습니다 a
유형 인 A
또는 A*
심지어 A&
(통화 별 참조). 많은 조합이 가능하며 모두 다르게 작동합니다.
나는 운영자의 & 주소를 알지 못하는 사람들로부터이 안티 패턴을 보았다. 포인터가있는 함수를 호출해야하는 경우 항상 힙에 할당하여 포인터를 얻습니다.
void FeedTheDog(Dog* hungryDog);
Dog* badDog = new Dog;
FeedTheDog(badDog);
delete badDog;
Dog goodDog;
FeedTheDog(&goodDog);
힙을 매우 중요한 부동산으로 취급하고 매우 신중하게 사용하십시오. 기본 규칙은 가능할 때마다 스택을 사용 하고 다른 방법이 없을 때마다 힙을 사용하는 것입니다. 스택에 객체를 할당하면 다음과 같은 많은 이점을 얻을 수 있습니다.
(1). 예외의 경우 스택 해제에 대해 걱정할 필요가 없습니다.
(2). 힙 관리자가 필요로하는 것보다 더 많은 공간을 할당하여 발생하는 메모리 조각화에 대해 걱정할 필요가 없습니다.
스택에 할당 할 수있을 때 (힙에) 새로 만들 이유가 없습니다 (어떤 이유로 든 작은 스택이 있고 힙을 사용하려는 경우가 아니라면).
힙에 할당하려는 경우 표준 라이브러리에서 shared_ptr (또는 그 변형 중 하나) 사용을 고려할 수 있습니다. shared_ptr에 대한 모든 참조가 존재하지 않으면 삭제 작업을 처리합니다.
다른 누구도 언급하지 않은 추가 이유가 있는데, 왜 동적으로 개체를 만들도록 선택할 수 있는지에 대한 것입니다. 동적 힙 기반 객체를 사용하면 다형성 을 사용할 수 있습니다 .
Visual Studio에서 동일한 문제가 발생했습니다. 다음을 사용해야합니다.
yourClass-> classMethod ();
보다는 :
yourClass.classMethod ();