저도 처음에 MEC++을 생각했는데 생각보다 까다롭군요. base class의 소멸자를
private로 하면 아예 상속을 할 수 없고, protected로 하면 그것만으로는 derived
class를 스택에 생성하는 것을 막을 수 없으니까요.
derived class의 소멸자도 protected로 만드는 방법밖에 생각이 나지 않는군요.
그런데 bugiii님도 이미 이 방법은 생각하셨겠죠.
저도 처음에 MEC++을 생각했는데 생각보다 까다롭군요. base class의 소멸자를
private로 하면 아예 상속을 할 수 없고, protected로 하면 그것만으로는 derived
class를 스택에 생성하는 것을 막을 수 없으니까요.
derived class의 소멸자도 protected로 만드는 방법밖에 생각이 나지 않는군요.
그런데 bugiii님도 이미 이 방법은 생각하셨겠죠.
스택에 만들어지는 것을 강제할 수는 없지만 소용없도록 하는 것을 다음과 같이 만들어 보았습니다. 목표는 라이브러리 사용자가 쓰레드를 생성하는 객체를 스택에 만드는 실수를 방지하는 것입니다.
라이브러리의 다른 파일들과 엮여있어서 바로 컴파일은 안되겠지만 의미만 한번 보시고 같이 고민 부탁드립니다.
ThreadStart 자체를 좀 더 개선하면 스택 크기를 담는 홀더 객체를 이용해서 디폴트 인자 비슷하게 흉내도 내보고 싶고, ThreadStart 의 리턴값이 생날짜의 쓰레드 핸들이 아니라 좀 더 의미있는 ThreadControl 같은 클래스의 생성자 인자 정도를 지원해서 detach 나 join 같은 것을 구현해보려고 합니다.
잠시 생각해 봤는데.. portable한 방법으로는 힘들 것 같습니다. 일단 전 C++ 전문가도 아니다보니.. :? stack에 class instance를 만들면 안되게 하는 방법보다, 무조건 heap에 만들게 하는 것은 좀 더 쉬울 것 같아서.. 다음과 같이 해 봤는데.. 음.. 조언 바랍니다:
compile-time 이 아니라 runtime에 강제하는 방법이구요.
그런데 static 이 아닌 멤버 변수 dyn_created 가 false(0) 으로 초기화된다는 보장이 없고, reinterpret_cast 해서 생성자 호출전에 dyn_created 를 접근하는것은 말씀하신데로 portable 한 방법은 아닌것 같습니다.
cinsk wrote:
잠시 생각해 봤는데.. portable한 방법으로는 힘들 것 같습니다. 일단 전 C++ 전문가도 아니다보니.. :? stack에 class instance를 만들면 안되게 하는 방법보다, 무조건 heap에 만들게 하는 것은 좀 더 쉬울 것 같아서.. 다음과 같이 해 봤는데.. 음.. 조언 바랍니다:
굳이 new operator를 재작성(overloading인지 overriding인지.. 철자가 틀리려나.. ㅡ.ㅜ) 해서 heap을 체크할 필요성이 있나 모르겠군요...
그 나름대로의 장점이 있기는 하지만...
컴파일타임에 에러를 확인 못하는거.. 너무 치명적이지 않을까 합니다.
stack에 만들지지 않는 방법을 찾는다면...
그냥 이렇게 하는게 편할듯 하네요...
class CHeapOnly
{
CHeapOnly() { }
public:
~CHeapOnly() { }
static CHeapOnly* CreateObject() {
return new CHeapOnly();
}
};
CHeapOnly stackobject; // compile time error
CHeapOnly* heapobject = CHeapOnly::CreateObject(); // no error
WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra
굳이 heap을 체크할 필요성이 있나 모르겠군요...
stack에 만들지 는 방법을 찾는다면...
그냥 이렇게 하는게 편할듯 하네요...
class CHeapOnly
{
CHeapOnly() { }
public:
~CHeapOnly() { }
CHeapOnly* CreateObject() {
return new CHeapOnly();
}
}
CHeapOnly stackobject; // compile time error
CHeapOnly* heapobject = CHeapOnly::CreateObject(); // no error
그렇게 간단히 해결되지 않습니다. 이것은 소멸자를 private으로 만든 것과 본질적으로
같습니다. 문제는 이 클래스를 상속받은 클래스에서도 힙에만 생성되도록 강제하는
것이죠. 그런데 이 구조는 상속 자체가 안됩니다. 만약 CHeapOnly의 생성자를
protected로 만든다고 해도
class Derived : public CHeapOnly { };
Derived d; // this should be an error, but it's not
소멸자를 private가 아니라 protected로 하면 되지 않나요?
답을 거의 알고 계신데 뭔가 착각하신듯...
MEC++ Item 27을 보세요.
Re: 소멸자를 private가 아니라 protected로 하면 되지 않나요?
그걸로 부족해서 드리는 질문입니다. 소멸자를 protected 로 한다고 해도 상속받은 클래스의 소멸자가 public 이라면 상속 받은 크래스를 스택에 만들 수 있다는 문제 때문입니다.
저도 처음에 MEC++을 생각했는데 생각보다 까다롭군요. base cla
저도 처음에 MEC++을 생각했는데 생각보다 까다롭군요. base class의 소멸자를
private로 하면 아예 상속을 할 수 없고, protected로 하면 그것만으로는 derived
class를 스택에 생성하는 것을 막을 수 없으니까요.
derived class의 소멸자도 protected로 만드는 방법밖에 생각이 나지 않는군요.
그런데 bugiii님도 이미 이 방법은 생각하셨겠죠.
[quote="doldori"]저도 처음에 MEC++을 생각했는데 생각보
네, 그렇게 하면 되는데 사용자들이 그렇게 안할 확률이 엄청 높다는게 문제라서요.
원하시는 답은 아니지만..
융통성을 발휘해서
이건 어떻습니다?
Life rushes on, we are distracted
굳이 스택에 만들어지지 않도록 강제하는 방법이 있지는 않은것으로 알고 있
굳이 스택에 만들어지지 않도록 강제하는 방법이 있지는 않은것으로 알고 있습니다.
그보다 스택에 강제할 수 있다는 얘기를 어디서도 들어보지는 못했군요...
강제할 수 있나요 ?
WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra
[quote="htna"]굳이 스택에 만들어지지 않도록 강제하는 방법이
굳이 필요하거든요. 사용자의 실수를 막고 싶은 (거의 대부분 실수를 할 것이 예상되는 부분) 라이브러리 제작자의 안타까움이랄까요...
스택에 강제하는 것은 delete 연산자를 숨기는 것으로 어느정도 시도해 볼 수 있지 않을까 합니다.
Re: 원하시는 답은 아니지만..
이 코드는 컴파일이 안되겠는데요.
Re: 원하시는 답은 아니지만..
대충생각해서 vc7.1에서만 컴파일해보고 올렸네요.. 엉터리 코드입니다. :oops:
그런데 동적할당은 안되고 스택에만 만들어지게는 할 수 있습니다.
아래처럼. exception handler에서 동적할당하는 것을 막게 하고싶을때 이렇게 하면 되겠죠.
Life rushes on, we are distracted
스택에 만들어지는 것을 강제할 수는 없지만 소용없도록 하는 것을 다음과
스택에 만들어지는 것을 강제할 수는 없지만 소용없도록 하는 것을 다음과 같이 만들어 보았습니다. 목표는 라이브러리 사용자가 쓰레드를 생성하는 객체를 스택에 만드는 실수를 방지하는 것입니다.
라이브러리의 다른 파일들과 엮여있어서 바로 컴파일은 안되겠지만 의미만 한번 보시고 같이 고민 부탁드립니다.
ThreadStart 자체를 좀 더 개선하면 스택 크기를 담는 홀더 객체를 이용해서 디폴트 인자 비슷하게 흉내도 내보고 싶고, ThreadStart 의 리턴값이 생날짜의 쓰레드 핸들이 아니라 좀 더 의미있는 ThreadControl 같은 클래스의 생성자 인자 정도를 지원해서 detach 나 join 같은 것을 구현해보려고 합니다.
잠시 생각해 봤는데.. portable한 방법으로는 힘들 것 같습니다.
잠시 생각해 봤는데.. portable한 방법으로는 힘들 것 같습니다. 일단 전 C++ 전문가도 아니다보니.. :? stack에 class instance를 만들면 안되게 하는 방법보다, 무조건 heap에 만들게 하는 것은 좀 더 쉬울 것 같아서.. 다음과 같이 해 봤는데.. 음.. 조언 바랍니다:
일단, 일부러 dyn_created member를 초기화하지 않고, operator new()에서 강제로 이 것을 설정하는 방식인데... C++ 잘 아시는 분들이 조언바랍니다. 일단 Linux gcc에서 동작을 하긴 하는데.. :wink:
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
compile-time 이 아니라 runtime에 강제하는 방법이구요.
compile-time 이 아니라 runtime에 강제하는 방법이구요.
그런데 static 이 아닌 멤버 변수 dyn_created 가 false(0) 으로 초기화된다는 보장이 없고, reinterpret_cast 해서 생성자 호출전에 dyn_created 를 접근하는것은 말씀하신데로 portable 한 방법은 아닌것 같습니다.
runtime 에 강제하는 방법
재밌는 주제고 뉴스그룹에서 당연히 다뤄 봤을거 같아서 찾아 봤습니다.
http://groups.google.co.kr/group/comp.lang.c++.moderated/browse_thread/thread/f19ff3f0b4db1b95/3c43f5d933ad658c?q=force+stack+derived&rnum=2&hl=ko#3c43f5d933ad658c
compile-time에 강제 하는 것은 힘들것 같고,
위 뉴스그룹 글의 마직막에 포스팅한 사람이 제안한 다음과 같은 방법이 표준에 부합한다면 한가지 방법이 될 수 있겠네요.
(cinsk 님이 제안한 방법의 좀더 정확한 표현이라고 볼수 있겠네요)
:oops: 이런 초보적인 실수를 하다니...pinetr2e님이 말씀하신
:oops: 이런 초보적인 실수를 하다니...pinetr2e님이 말씀하신 것처럼 초기화되지 않았으니 문제가 심각하군요. 뉴스 그룹에서 보셨다는 방법처럼 증가/감소하는 방식을 쓰는 게 더 나을 듯 싶습니다.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
pinetr2e님이 소개하신 방법이 괜찮아 보이는군요. 이식성에도 문제가
pinetr2e님이 소개하신 방법이 괜찮아 보이는군요. 이식성에도 문제가 없을 것 같습니다.
저는 다른 얘기를 하고 싶은데 ThreadProc() 함수에 예외 안전을 고려하시는 것이
어떨까 합니다.
그리고 템플릿으로 만든 몇 개의 함수의 의미가 재미있군요. factory pattern 비슷한
효과를 내는 것 같네요.
굳이 new operator를 재작성(overloading인지 overr
굳이 new operator를 재작성(overloading인지 overriding인지.. 철자가 틀리려나.. ㅡ.ㅜ) 해서 heap을 체크할 필요성이 있나 모르겠군요...
그 나름대로의 장점이 있기는 하지만...
컴파일타임에 에러를 확인 못하는거.. 너무 치명적이지 않을까 합니다.
stack에 만들지지 않는 방법을 찾는다면...
그냥 이렇게 하는게 편할듯 하네요...
WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra
[quote="htna"]굳이 heap을 체크할 필요성이 있나 모르겠군요
그렇게 간단히 해결되지 않습니다. 이것은 소멸자를 private으로 만든 것과 본질적으로
같습니다. 문제는 이 클래스를 상속받은 클래스에서도 힙에만 생성되도록 강제하는
것이죠. 그런데 이 구조는 상속 자체가 안됩니다. 만약 CHeapOnly의 생성자를
protected로 만든다고 해도
[quote="doldori"][quote="htna"]굳이 heap을
상속이라는 제한이 있었군요..
ㅎㅎ
너무 직접적인 요구를 잊었네요...
orz
WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra
[quote="doldori"]pinetr2e님이 소개하신 방법이 괜찮아
그렇죠!!! delete 해야 한다는데 급급한 나머지 그걸 빠트렸군요. 좋은 지적 감사합니다. 그리고 static_cast 가 되는군요. 고맙습니다.
네, 목표를 정하고 다시 생각해보니 자연스럽게 그런 형태가 나오더군요. 원래의 주제처럼 동적 할당을 강제하는 것이 아니라 제시한 형태로 사용하지 않으면 동작하지 않도록 하면 된다는 것에 초점을 맞춰보았습니다.
제가 원하는 목표를 제시하지 않고 너무 일반적인 주제로 질문을 올려서 질문 자체가 잘못된 것이 아닌가 걱정이 되긴 했지만, 다른 여러분의 좋은 의견도 있고 새로운 아이디어도 얻을 수 있어서 좋았습니다.
pinetr2e 님이 제시하신 방법도 좋아보입니다. new / delete 의 다른 형태도 지원한다면 좀 더 완벽해질 것 같습니다.
하여튼, 사용자에게 어떤 형태로든 사용법을 강제해서 잘못 사용하는 것을 방지하고자 하는 것은 어느정도 만족했다고 생각합니다. 이제 조금 더 다듬어서 마무리 해야겠습니다.
역시나 라이브러리 제작이라는 것이 그 구현 자체도 고민이 되는 것이지만 사용자가 실수할 부분을 미연에 방지하는 것 또한 시간이 많이 걸리고 노력이 필요한가 봅니다.
그럼, 좋은 휴일 되시구요. 다시 한번 좋은 의견 감사드립니다.
댓글 달기