저는 프로그래밍에 익숙하지 않지만 Java로 작업 한 후에 저는 C++로 돌아가고 포인터가 아닌 클래스 변수에 관해 혼란스러워합니다.
혼란은 힙에있는 데이터와 힙에있는 데이터의 조합에서 비롯된 것으로 보입니다. 이것은 혼란의 흔한 원인입니다.
게시 한 코드에서 bars
은 (는) 포인터가 아닙니다. 그것이 클래스 스코프에 있기 때문에 그것을 포함하는 객체 (testbars
)가 파괴 될 때까지 존재할 것입니다. 이 경우 testbars
이 스택에 만들어 지므로 범위가 얼마나 깊게 중첩되었는지에 관계없이 범위를 벗어날 때 파괴됩니다. 그리고 testbars
이 파괴되면 testbars
의 하위 객체 (부모 클래스이거나 testbars
객체에 포함 된 객체)는 소멸자가 정확하게 정의 된 순서대로 정확하게 실행되도록합니다.
이것은 C++의 매우 강력한면입니다. 네트워크 연결을 열고, 힙에 메모리를 할당하고, 파일에 데이터를 쓰는 10 라인 생성자가있는 클래스를 상상해보십시오. 클래스의 소멸자가 그 모든 것을 취소했다면 (네트워크 연결을 닫고, 힙의 메모리 할당을 해제하고, 파일을 닫는 등) 상상해보십시오. 이제이 클래스의 객체를 만드는 것이 생성자의 중간에서 실패했다고 가정합니다 (예 : 네트워크 연결이 끊어짐). 소멸자의 어떤 줄이 성공한 생성자 부분을 실행 취소할지 프로그램에서 어떻게 알 수 있습니까? 이를 알 수있는 일반적인 방법이 없으므로 해당 객체의 소멸자가 실행되지 않습니다.
이제 10 개의 개체가 포함 된 클래스를 상상해보십시오. 각 개체의 생성자는 롤백해야하는 작업 (네트워크 연결 열기, 힙에 메모리 할당, 파일에 데이터 쓰기 등)을 수행합니다. 이러한 객체 각각에 대한 소멸자에는 작업을 롤백하는 데 필요한 코드가 포함됩니다 (네트워크 연결을 닫고, 객체를 할당 해제하고, 파일을 닫는 등). 5 개의 개체 만 성공적으로 생성되면 5 개의 개체 만 파괴해야하며 해당 소멸자 은 정확한 시점에으로 실행됩니다.
testbars
이 new
을 통해 힙에 작성된 경우 delete
을 호출 할 때만 파괴됩니다. 일반적으로 객체가 생성 된 범위보다 오래 걸리지 않는 한 스택에 객체를 사용하는 것이 훨씬 쉽습니다.
어느 것이 나를 Foo::bar
으로 가져옵니다. Foo::bars
은 힙의 오브젝트를 나타내는 map
입니다. 글쎄, 그것은이 코드 예제에서 힙에 할당 된 객체를 참조하는 포인터를 참조합니다 (포인터는 스택에 할당 된 객체를 참조 할 수도 있음).이 포인터가 참조하는 객체를 게시 한 예에서는 결코 delete
d가 아니며 이러한 객체가 힙에 있기 때문에 작은 메모리 누수가 발생합니다 (운영 체제가 프로그램 종료시 정리하는). STL에 따르면, Foo::bar
은 이 아니고,delete
포인터와 같다. 포인터는 파괴되었을 때를 가리킨다. Boost에는이 문제에 대한 몇 가지 해결책이 있습니다. 귀하의 경우에는 단순히 이러한 개체를 힙에 할당하지 않는 것이 가장 쉽습니다.
#include <iostream>
#include <map>
using std::map;
using std::cout;
class Foo {
public:
Foo() {
// normally you wouldn't use the parenthesis on the next line
// but we're creating an object without a name, so we need them
bars[0] = Bar();
bars[0].id = 5;
}
~Foo() { }
struct Bar {
int id;
};
void set_bars(map<int,Bar>& b) {
bars = b;
}
void hello() {
cout << bars[0].id << endl;
}
protected:
map<int,Bar> bars;
};
int main() {
Foo foo;
foo.hello();
map<int,Foo::Bar> testbars;
// create another nameless object
testbars[0] = Foo::Bar();
testbars[0].id = 10;
foo.set_bars(testbars);
foo.hello();
return 0;
}
"bars.clear();"를 추가하면됩니다. freeBarsMemory()의 끝에서 사용하기에 조금 더 안전합니다. –