나엑스 님이 쓰신 글 :
: vector에다가 TButton 100개 만들려면
:
: vector<TButton> btns(100,TButton(this))
: 요렇게 하면 되잖습니까, 근데 이 것이 vcl 이기 땜시 new 를 사용해야 된다구 컴파일 에러가 나타나 컴파일이 않됩니다.
VCL 객체는 본래 오브젝트 파스칼 객체이므로 오브젝트 파스칼의 성질을 가집니다. 즉, 오브젝트 파스칼 객체는 스택에 만들 수 없고(자동 변수) 반드시 new를 사용해서 힙에만 만들 수 있습니다.
(원래 델파이가 나오기 전의 터보 파스칼 시절에는 스택에도 만들 수 있었지만, 델파이가 나오면서 문법이 변했습니다.)
:어차피 다른 for_each 알고리즘으로 각각 생성해줘도 되나 stl을 최대한 깔끔이 이용해 보구 싶어서요 방법이 없을 까요?
STL 컨테이너는 객체(의 값)을 저장하는 용도로 만들어진 것이지(객체의 값을 복사해서 넣습니다. 이러한 관점을 '값 의미론'이라고 합니다.), 객체의 포인터를 저장하기(참조 의미론)에는 알맞지 않습니다.
어쨌든 new로 생성한 객체의 포인터들을 STL 컨테이너에 저장하려면,
다음과 같이 루프를 사용하거나, 루프 대신 for_each 알고리듬을 써야 합니다.
void TForm1::doSomething()
{
vector<TButton*> btns;
for (int i=0; i < 100; ++i)
btns.push_back(new TButton(this));
... // btns를 사용하는 코드를 넣습니다.
// TButton::Parent 속성을 제대로 지정해야 화면에 표시되는 건 아실테죠?
} // 주의: 만약 TButton이 TComponent의 자손이 아닌 클래스라면, 여기서 메모리 누수가 발생합니다. 다행히 생성자(TComponent::TComponent(TComponent* AOwner))에서 Owner로 this를 지정했기 때문에 메모리 누수가 발생하지 않습니다만, 버튼들은 삭제되지 않고 그대로 남아있게 됩니다. 수동으로 delete할 수도 없지요. 즉, 폼(Form1)이 이 버튼들의 Owner이므로 폼이 삭제될 때 함께 삭제됩니다.
VCL 객체의 저장에는 STL 컨테이너도 좋지만, TComponentList나 TObjectList를 쓰는 것이 델파이 코드와의 호환을 위해서는 좋습니다. 물론 STL이 제공하는 다른 기능(알고리듬과 같은)을 쓸 수는 없겠지요.
위에서 VCL 컴포넌트가 아닌 객체의 포인터를 저장하는 STL 컴포넌트의 메모리 누수 문제를 지적했습니다. 이것을 해결하는 가장 단순한 방법은 일일히 수동으로 delete를 써서 삭제하는 것이지만, 예외 발생시에는 메모리 누수가 발생할 수 밖에 없습니다.
이 문제를 해결하는 가장 좋은 방법은 Boost 라이브러리(
http://boost.org )의 share_ptr 스마트 포인터를 쓰면 됩니다. 이것만 있으면 자바나 C#의 가비지 컬렉션도 부럽지 않죠. 오히려 더 낫다고 말할 수 있습니다.
이러한 내용에 대해서는 Effective STL, Item 7을 참고하기 바랍니다.