#include <iostream>
#include <string>
using namespace std;
#define SAFE_DELETE(A) { if(A != NULL) { delete (A); A = NULL; } }
class MyString
{
public:
string* m_str;
MyString() { m_str = NULL; }
MyString(const char* p) { m_str = new string(p); }
virtual ~MyString() { SAFE_DELETE(m_str); }
};
void write(MyString s)
{
if (s.m_str != NULL)
cout << *s.m_str << endl;
}
int main()
{
MyString s = "test";
write(s);
return 0;
}
댓글 14
-
홍문화
2011.09.14 11:17
-
홍문화
2011.09.14 14:40
네 에러 나는줄 알았는데 안나네요. ㅋ
-
무명
2011.09.14 14:37
매크로에서 do while() 문을 사용하지 않아서 에러가 발생하는 이유는
if() 문 뒤에 ;이 붙으면 else 문이나 else if() 문이 if() 문과 이어지지 않기 때문에
뒤의 독립되어 버린 else 문이나 else if() 문에서 에러가 발생하는 것입니다.
뒤에 else 문이나 else if() 문이 없다면 에러가 발생하지 않습니다.
물론 위의 소스 코드에서도 매크로에서 do while() 문 사용을 권장하지만,
위의 소스 코드에서 지적하신 부분은 에러가 아닙니다.
실제로 if(something) { do something };;;;;;;;;; 컴파일해보세요. 뒤에 else 문이나 else if() 문이 없다면 에러가 발생하지 않습니다.
-
하상은
2011.09.14 13:25
코드를 잘못보고 잠시 딴소리를 했다가 수정합니다..ㅋ
적절한 복사생성자가 없어서 write 함수에 진입할때 MyString 의 인스턴스를 만들며 m_str 값을 그냥 복사할듯 하네요..그렇게 되면 write 함수가 종료되면서 m_str 의 메모리 할당을 해제할테고 main 함수가 종료될 때 m_str 을 제거하려 시도하면서 런타임 에러가 발생할듯 합니다
-
하상은
2011.09.14 15:53
한수배워갑니다.. ^^
-
홍문화
2011.09.14 15:42
켘! 실력은 무슨 제 소개 보시면 아시겠지만 저 완전 초보입니다.
고수가 되면 저 밥줄 끊깁니다. 자만해져서 공부를 안하게 될테니까요. ㅋㅋ
정답을 구하고자 올린 글이 아니라 생각했기에 코드를 대충 보고 댓글을 달았습니다.
정답을 구하고자 올린 글이었다면 최소한 코드도 돌려보고 진지하게 생각을 해본 후 댓글을
달아야 한다고 생각합니다. 목적에 부합하지 않은 잘못된 정보 전달은 상대방에게 막대한 피해를
줄 수도 있으니까요.
개인적인 생각입니다만 조회수가 50이 넘어가는데 댓글을 다시는 멤버님들이 아무도 안계셔서
물꼬를 좀 터보고 싶었습니다. 정답을 맞추는 것보다 더 중요한 것이 멤버들간에 정보 교류를 통해
정답을 찾아 가는 과정이 아닐까 싶은데 너무 결과만을 중요시 하는것이 아닌가 합니다. ^^;
-
하상은
2011.09.14 15:11
네..일반적인 클래스 설계 패턴으로 미루어보면 wrtie 함수의 인자로 생성된 MyString의 m_str 이 가리키는 주소가 main 함수에서 생성된 MyString 의 인스턴스에 들어있는 m_str 과 같아지지 않도록 복사생성자를 이용해 새로 메모리 할당과 해제가 되게 하는게 적절할듯 합니다.
하지만 다른 방법들로도 해결은 가능한 문제이죠..
홍문화님 실력은 익히 알고있는데 아무래도 주요 분야가 분야이다보니 클래스보단 다른쪽에 눈이 더 가셨나봐요 ^^
-
홍문화
2011.09.14 14:33
아... 복사 생성자 문제였군요. ㅋㅋ
-
이경문
2011.09.14 19:36
implicit copy constructor는 멤버의 복사만 이루어 지기 때문에 m_str 의 포인터만 복사가 되어 나중에 실제로 하나의std::string 객체가 2번 delete 되는 버그입니다(access violation error 혹은 segmentation fault 에러가 발생). ^^
해결하는 방법은 copy constructor를 명시해 줘서 std::string 객체를 복사(duplicate)해 주는 방법이 있고, 혹은 자신이 만든 클래스의 복사를 방지하기 위해서 copy constructor를 private이나 protected 영역에서 선언을 하여 컴파일 타임에서 객체 복사를 방지할 수 있는 방법도 있습니다.
{ ... private: MyString(const MyString & rhs) {} // noncopyable MyString& operator = (const MyString& rhs) {} // noncopyable ... };
참고하시기 바랍니다. ^^
-
이경문
2011.09.14 22:00
네, 일부러 못쓰게 copy constructor를 막어 놓은 거죠. ^^
-
하상은
2011.09.14 19:59
좋은 예 입니다. 그런데 private 으로 옮겨버리면 저 위의 코드는 고치기전엔 못쓰겠네요
저 코드의 가장 큰 문제는 포인터의 남용인듯합니다..m_str 을 동적할당 하지 않는게 복사생성자에 이은 두번째 정답이 아닐까 싶네요
-
홍문화
2011.09.14 20:52
그러네요. 복사 생성자를 사용하지 못하게 만들면 원래 소스가 동작을 못하게 될텐데...
m_str을 포인터가 아닌 멤버 객체로 만들어주면 디폴트 복사 생성자 만으로도 이상 없이 동작 하네요.
그런데 정말 궁금한건 왜 이 문제를? ^^;
(나쁜 의도는 전혀 없습니다. 오해 하실까봐. ㅋ)
-
홍문화
2011.09.14 23:05
그렇군요. 순수 language 관련 글은 본적이 없어서 뭘까? 궁금해 했습니다. ㅋ
데브피아나, KLDP 같은 곳에 가면 language관련 질문, 답변이 많아서 대부분 그곳을 애용 하시더라구요.
C++에서 멀어진지 한참 되었는데 좋은 공부 되었습니다. ^^;
-
이경문
2011.09.14 21:51
third party library를 가져다 쓰는데, memory 에러가 자꾸 나서 어디서 '버그가 있지?' 찾아 보다가 발견을 했습니다. 자칫 많은 사람들이 비슷한 경험을 할 것 같아서 문제를 내어 본 겁니다. ^^
.