[완료] C++ 얕은복사에 대해서
글쓴이: romaangel / 작성시간: 토, 2010/07/03 - 5:46오후
얕은 복사와 깊은 복사의 차이점을 알기위해서 아래와 같이 짜봤습니다.
#include <iostream> #include <string> using namespace std; class oop { public: char* str; oop(); oop(const oop& pt); void print(); }; oop::oop(const oop& pt) { str=pt.str; ///////////// <-여기서 주소값을 주기때문에 얕은 복사가 아닌가요? } oop::oop() { str="감자"; } void oop::print() { cout << str << endl; } int main() { oop a; a.print(); oop b=a; b.print(); cout << &a.str << endl << &b.str << endl; a.str="수건"; cout << a.str << endl << b.str << endl; return 0; }
얕은 복사라고 생각하고 막상 실행했더니 2개의 변수가 따로 메모리를 사용하네요.
제가 뭘 착각한 걸까요??
Forums:
a.str = "수건"; 이
이 코드가 실행되면 a instance의 str멤버변수에는 "수건" 의 주소값이 들어가겠죠.
당연히 b.str과는 다릅니다. 거긴 "감자"의 주소가 들어있으니까요.
객체 복사와는 관계없습니다. 그냥 포인터 대입에 해당합니다.
혹시 &a.str과 &b.str이 다른 이유를 물으신건 아니겠죠?
언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net
언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net
복사생성자때문에
초기화하면서 복사생성자를 이용하기때문에
a.str의 주소를 복사해서 b.str에 넣는게 아닌건가요?
그래서 a.str과 b.str의 주소가 같다. 그래서 a.str의 값을 바꾸면 b.str의 값도 바뀐다...
이렇게 생각하고 있는데;;;;
소스를 어떻게 고쳐야 얕은 복사가 되나요?
oop b = a; 에서 b.str 이
에서 b.str 이 a.str 값(포인터)로 설정된 것은 맞지만, &a 와 &b가 다릅니다. 즉 서로 다른 객체라는거죠.
b.str을 바꿨을때 a.str이 같이 바뀌려면 reference를 사용하세요.
이러면 b는 a를 참조하기만 하고 실제 인스턴스는 하나가 됩니다.
그런데 원하시는게 이게 맞나요?
언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net
언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net
제가 원한건
두개의 객체가 따로 있지만 객체속 멤버 변수가 같은 메모리를 사용하는것을 원한건데요
즉, &a와 &b는 분명 주소가 틀리겠지만
a객체의 str의 주소가 가리키는 메모리가
b객체의 str이 가리키는 메모리와 같다. 이렇게요
위에 제시한 해결법을 써볼려고 했는데 안먹히네요;; C++을 시작한지 이틀돼서;;; 양해좀;;;
a --> p b -->
a --> p
b --> p
상태에서
a --> p
b --> q
가 되도록 바꾸신 거구요. 원하는 데로 하려면
a --> c
b --> c
c --> p
상태에서
c --> q
가 되도록 하면 되겠죠?
수건을 대입시키시기 전까지는 같은 주소를 가리킵니다만
수건을 대입시기키시기 전까지는 같은 주소를 가리킵니다만
수건을 대입하고 나서는 다른 주소를 가리키는게 맞는 동작입니다.
포인터 변수에 대한 대입 연산자(=)는 포인터 변수의 내용을 변경시킵니다.
포인터 변수가 가리키는 주소의 내용을 변경시키시고 싶으시다면
위의 소스에서는 사용이 불가능합니다만 memcpy 또는 strncpy와 같은 함수를 사용하셔야 합니다.
그리고 a와 b가 가리키는 주소가 같은지를 보고 싶으시다면
&a.str이 아닌 a.str의 값을 찍어보셔야 합니다.
...
우선, C++에서 가장 엄격하게 다루는 포인터와 레퍼런스에 대한 기본적인 지식이 부족하신것으로 보이며,
이런 상태로 코딩을 하면 당연히 치명적인 에러를 유발하는 코드를 작성하게되는 지름길이 될 것입니다.
차이점을 알아보죠.
1.포인터 - 포인터는 변수와 다르게 메모리 번지를 저장하는 공간이지만, "값을 저장한다."라는 점에서는 같다고 보시면됩니다.
char* a = "문자열";
char* b = "123";
a=b;
이때, a는 b의 주소값을 복사하여 똑같은 메모리번지를 갖고 있게 되는 상태일뿐이지,
a의 메모리 번지값을 바꾼다고, b의 메모리 번지값이 같이 바뀌지는 않습니다.
다만, 해당 "메모리 번지에 저장되어 있는 값"을 바꾼다면, a,b에 동시에 적용이 되겠죠?
결론: 위에서 a,b가 근본적인 변수로써 가지는 공간은 전혀 틀린 공간입니다.
다만, a라는 공간과 b라는 다른 공간에서 "메모리번지"라는 같은 값을 갖고 있을 뿐인 것입니다.
2.레퍼런스 - 위에서는 포인터 변수가 근본적으로 다른 저장공간을 가진다고 했습니다.
레퍼런스는 서로 다른 이름을 가졌지만, 위와 달리 "같은 공간"을 사용하는 변수입니다.
레퍼런스는 포인터 타입이 될수도 있고, 변수타입으로도 사용가능합니다.
다만, 레퍼런스는 반드시 초기화가 이루어져야되고, 초기화되어지지 않을 경우 이것은 에러로 인식되며,
컴파일러상에 출력됩니다.
하나의 값을 바꿨을때 다른값이 바뀌는 개념이라면 이는 레퍼런스로 구현하시면 됩니다.
ps.위에서 쓰여진 문자열상수들은 리터럴풀에 저장되므로, 변수처럼 소멸되지 않습니다.
답변 감사합니다.
조금더 공부를 해야될 것같네요 ^^
댓글 달기