C++ 이니셜라이저 목록에서 this 사용하면 안되나요?

곱단오빠의 이미지

class A {
   B b;
};
 
A::A() : b(this)
{
}

위와 같은 코드를 짰습니다. b를 this로 초기화 하는 라인에서
컴파일러가 warning을 주더군요. 이니셜라이저 목록에서 this가 사용되었다고.
이거 안되는건가요?

winner의 이미지

이런 것이 필요합니까?

곱단오빠의 이미지

두 클래스가 서로 양방향으로 억세스 하기 위해서 필요했습니다.

chadr의 이미지

가능은 하지만 좀 위험합니다..
생성자가 아직 마치지 않은 상태에서 this를 넘겨주게 되면 가상함수테이블 등의 데이터가 초기화 되지 않고 다른 멤버들도 초기화가 덜 끝난 상태이기 때문에 잘못하다간 시한폭탄이 될수 있습니다.

정 원하신다면 생성자에서 하지 마시고 생성을 다 끝난 시점에서 멤버 함수로 포인터를 넘기도록 하는게 좋습니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

익명 사용자의 이미지

class A {
   B *b;
};

김일영의 이미지

그 폐해를 아실 수 있을 겁니다.

간단히 말해서 A의 자식 클래스 B를 만들고 B의 인스턴스를 만들면
문제의 b 멤버변수에는 B의 인스턴스의 this가 들어가는게 아니라
클래스 A에 해당하는 this가 들어갑니다.

B는 A에 그냥 추가만 되는 것일텐데 어차피 this도 같은 것 아니겠나 싶지만
실제로 해보면 그렇지 않은 경우가 많이 나타납니다.

결론은... 저렇게 하지 마십시오.

musiphil의 이미지

다들 부정적인 쪽으로만 말씀해 주셨는데요.

결론적으로는 적법하고, 사용 가능하며, 또 필요한 경우 쓰지 않을 수 없는 구문입니다.
다만, 생성자의 초기화 목록에서는 아직 개체의 생성이 완료되지 않은 시점이기 때문에
주소를 단지 포인터 값으로만 다루고 이를 이용하여 개체를 참조하지는 말아야 합니다.

위와 같은 일이 발생하는 가장 흔한 상황이, 내가 만들어질 때 내 주소를 상대방에게
넘겨주면서 나중에 뭔가를 호출해 달라고(callback) 하는 것인데, 이 경우 상대방은
내 주소를 나중을 위해 보관만 해 두지, 주소를 받자마자 내 데이터 멤버를 참조한다거나
내 멤버 함수를 호출한다거나 하지는 않는 것이 보통입니다. 이런 경우라면 얼마든지
안심하고 사용하실 수 있습니다.

결국 상대방의 생성자가 내 주소를 가지고 무슨 일을 하느냐에 따라 달라지는 것인데,
컴파일러가 그 내부까지 살펴보고 안전하다 또는 위험하다 판단을 내릴 수 있을 정도로
똑똑하지 않기 때문에, 그냥 위험하게 사용될 가능성이 있는 저 구문에 대해서는 무조건
경고를 내보내는 정도로만 그치는 것입니다.

에러로 금지하지 않고 경고만 내보내는 것에는 이유가 있습니다.
물론 코드가 경고 없이 깔끔하게 컴파일되는 것이 좋기는 하지만,
경고의 내용을 제대로 이해하지 못하고,
경고를 일으킨 코드를 무조건 금기시하는 것은 바람직하지 못한 태도입니다.
때에 따라서는 경고를 무시하는 것도 필요합니다.

김일영의 이미지

바로 앞에 제가 썼다시피 자식 클래스의 인스턴스를 만들 경우에는 그 인스턴스의 this값이 아니라 올바르지 않은 참조가 들어갑니다.
이 값을 참조하는 시점이나 어떤 멤버를 참조하느냐 등이 문제가 아니라 값 자체가 틀린 값이 된다는 것입니다. 그렇다고 해서 비록 틀린 값이지만 유일성이 보장되느냐 하면 그렇지도 않습니다. (그런 규정은 없습니다.)
여튼... 이로 인한 문제를 직접 경험해보시면 적법하다고 말씀 못하실 겁니다.

musiphil의 이미지

실제로 써 보면 문제가 없다는 얘기는,
comp.lang.c++.moderated 그룹 등에서 검색해 보시면
많은 사람들이 하는 것을 찾아보실 수 있고요.

그렇다고 옳다는 것이 증명되는 것은 아니니,
판단의 최종 근거가 되는 표준 문서를 인용하겠습니다.

ISO/IEC 14882:2003, 12.6.2/7 wrote:
[Note: because the mem-initializer are evaluated in the scope of
the constructor, the this pointer can be used in the expression-list
of a mem-initializer to refer to the object being initialized. ]

이렇게 표준에서 명시적으로 가능하다고 이야기하고 있습니다.

값 자체가 틀린 값이 된다고 하셨는데, 실제로 그렇게 될 수 있는 경우를
"자식 클래스의 인스턴스를 만들 경우"라는 막연한 표현보다도
구체적이고도 간단한 코드로 보여주시면 좋겠습니다.

김일영의 이미지

자꾸 왜 전혀 관계 없는 문구를 근거라고 제시하시는지 모르겠습니다.
그 문구는 this 포인터라는 것을 생성자에서 쓸 수 있느냐 없느냐 하는 것 뿐이죠.
이 문제와 관계 없다는걸 아시는것 같은데도 그러시는 이유를 모르겠군요.

중요한건 상속받은 클래스가 초기화될 때는 부모 클래스의 this 값과는 달라질 수가 있다는겁니다.
그러면 class A 부분이 초기화되었을 때의 this 값을 받아놔봐야 쓰레기값이 되겠지요.
제가 이 문제를 직접 겪어봐서 저 역시 여러 곳을 뒤져봤기 때문에 알고 있습니다.
Stroustrup의 홈페이지에서까지 확인해봤습니다.

class A
{
public:
A *a;
};
A::A() : a(this) {}

class B : public A
{
public:
B *b;
};
B::B() : b(this) {}

뭐 대충 이런 식으로 클래스를 만들었다 치고

B b1;

이렇게 인스턴스를 만들어서 b1.a 와 b1.b 를 비교해볼 때 두놈이 같아야 할 것 같지요?
하지만 C++ 에는 그래야한다는 규정이 없습니다.
(사실 C++은 다중상속도 있으니 근본적으로 그럴 수가 없겠죠...)
그래서 실제로 다른 경우가 생깁니다.

제가 당했던 경우가 바로 그런 경우였습니다.

문제가 생기는걸 뻔히 알면서 부정적이지 않아야 할 이유라도 있나요?

익명 사용자의 이미지

BJ의 홈페이지에는 초기화할 때 this를 쓰면 안된다는 얘긴 없던데요?
김일영씨의 글을 읽어봐도 정확히 어떤 문제가 생긴다는 얘긴지 잘 모르겠는데
제 추측으로는 base class의 생성자에서는 virtual function을 호출할 때의
문제를 말씀하시는 듯합니다.
http://www.research.att.com/~bs/bs_faq2.html#vcall
잘 알려진 문제지만 이거야말로 지금 주제와는 관계없는 얘기지요.
대충 만든 코드 말고 진짜로 문제가 생기는 코드를 올려보세요.

아, 밑에 문제없는 코드도 보고 싶으시다고 하셨군요.
김일영씨가 올린 코드가 바로 문제없는 코드입니다. :-)

익명 사용자의 이미지

오타 났네요.
BJ가 아니라 BS입니다.

김일영의 이미지

저걸 보고 무슨 말인지 모른다면 토론에 낄 자격도 없을 터.
말장난 할 시간에 한번 두드려서 돌려 보셔.

제 추측으로는 base class의 생성자에서는 virtual function을 호출할 때의
문제를 말씀하시는 듯합니다.
--> 저기 virtual 이란 글자나 나왔냐구. 혹시 컴맹?

아, 밑에 문제없는 코드도 보고 싶으시다고 하셨군요.
김일영씨가 올린 코드가 바로 문제없는 코드입니다. :-)
--> 밥은 먹고 다니냐?

김일영의 이미지

BJ의 홈페이지에는 초기화할 때 this를 쓰면 안된다는 얘긴 없던데요?
--> 애당초 이거 이야기한거 아니거등? 이래서 초등학교를 잘 나와야지.

김일영의 이미지

대충 만든 코드 말고 진짜로 문제가 생기는 코드를 올려보세요.
--> 똥인지 된장인지 찍어먹어도 모를 놈을 위한 코드 따위까지 만들어주고 싶진 않은데?

익명 사용자의 이미지

흠... 참 쉽게도 바닥을 드러내시는군요.
보아하니 더 얘기를 할 필요는 없을 듯하고
당신의 글은 캡처해둘 터이니 두고두고 마음을 닦는 거울로 쓰시기 바랍니다.

Quote:

저걸 보고 무슨 말인지 모른다면 토론에 낄 자격도 없을 터.
말장난 할 시간에 한번 두드려서 돌려 보셔.

제 추측으로는 base class의 생성자에서는 virtual function을 호출할 때의
문제를 말씀하시는 듯합니다.
--> 저기 virtual 이란 글자나 나왔냐구. 혹시 컴맹?

아, 밑에 문제없는 코드도 보고 싶으시다고 하셨군요.
김일영씨가 올린 코드가 바로 문제없는 코드입니다. :-)
--> 밥은 먹고 다니냐?

BJ의 홈페이지에는 초기화할 때 this를 쓰면 안된다는 얘긴 없던데요?
--> 애당초 이거 이야기한거 아니거등? 이래서 초등학교를 잘 나와야지.

대충 만든 코드 말고 진짜로 문제가 생기는 코드를 올려보세요.
--> 똥인지 된장인지 찍어먹어도 모를 놈을 위한 코드 따위까지 만들어주고 싶진 않은데?


김일영의 이미지

이미 익명으로 찌질 붙을때 바닥이 드러난거야...
캡쳐할 필요도 없어 간단해 좋구만.

musiphil의 이미지

김일영 wrote:
자꾸 왜 전혀 관계 없는 문구를 근거라고 제시하시는지 모르겠습니다.
그 문구는 this 포인터라는 것을 생성자에서 쓸 수 있느냐 없느냐 하는 것 뿐이죠.
이 문제와 관계 없다는걸 아시는것 같은데도 그러시는 이유를 모르겠군요.

관계 없지 않습니다.
그리고 단지 사실을 올바로 전하려는 것일 뿐, 괜히 궤변을 늘어놓는 것이 아닙니다.

"쓸 수 있기는 한데, 그 값은 쓰레기값일 수도 있다"라는 얘기를 저렇게 했겠습니까?
생성자의 초기화 목록에서, 초기화되고 있는 개체를 this 포인터로 가리킬 수 있다고 했습니다.
포인터 값으로 제대로 가리킬 수 있는데 그 포인터 값이 쓰레기값일 수는 없습니다.

김일영 wrote:
중요한건 상속받은 클래스가 초기화될 때는 부모 클래스의 this 값과는 달라질 수가 있다는겁니다.
그러면 class A 부분이 초기화되었을 때의 this 값을 받아놔봐야 쓰레기값이 되겠지요.

C++에서 개체의 주소는 초기화될 때 한번 정해지면 바뀌지 않습니다.
B가 A를 상속받았다면, B object 속에 들어 있는 A subobject의 주소(A*)와
B object의 주소(B*)는 다를 수 있습니다(특히 다중상속, 가상상속의 경우 흔합니다)만,
각각의 값은 모두 유효하고 또 변하지 않는 각각의 object의 고유한 주소입니다.

struct A { A* a; A() : a(this) {} };
struct B { B* b; B() : b(this) {} };
struct C : A, B { C* c; C() : c(this) {} };
C x;

위와 같은 경우, x.a, x.b, x.c를 초기화하는 데에 모두 this 포인터가 사용되었지만
다중상속의 특성상 x.c는 x.a와 x.b 둘 중 하나와는 필연적으로 다를 수밖에 없습니다.
(둘 모두와 다른 경우도 이론적으로 가능하지요. 굳이 그렇게 할 필요는 없지만.)
그렇다고 x.a, x.b, x.c 중 잘못된 값이 하나라도 있느냐 하면 절대 그렇지 않습니다.

위에서 만약 x.c가 x.b와 다르다고 하면, C* 형인 x.c가 B* 형으로 형변환되는 순간
그 값도 x.b와 같은 값으로 바뀔 수 있다는 사실은 이해하고 계십니까?

std::cout << x.c << '\n';
B* p = x.c;
std::cout << p << '\n'; // 위 값과 다름

김일영 wrote:
이렇게 인스턴스를 만들어서 b1.a 와 b1.b 를 비교해볼 때 두놈이 같아야 할 것 같지요?
하지만 C++ 에는 그래야한다는 규정이 없습니다.
(사실 C++은 다중상속도 있으니 근본적으로 그럴 수가 없겠죠...)
그래서 실제로 다른 경우가 생깁니다.

두 값이 같아야 한다고 한 적 없습니다. b1.a와 b1.b는 그 형이 다르니(A*와 B*)
물론 값이 다를 수 있습니다. 위와 같은 경우는 굳이 두 값을 다르게 만들 필요가 없으므로
많은 컴파일러에서 두 값이 같도록 레이아웃을 잡습니다만, 꼭 그래야 하는 것은 아닙니다.
특히나 다중상속, 가상상속의 경우 필연적으로 값이 달라져야 하는 부분이 생깁니다.

제가 전달해 드리려고 하는 점은, (두 값이 다를 수 있음에도 불구하고)
b1.a와 b1.b 모두가 적법한 값들이고 저런 식으로 생성자에서 값을 저장해 두었다가
나중에 그 값으로 A, B object를 참조하는 데에 아무런 문제가 없다는 것
입니다.

김일영 wrote:
Stroustrup의 홈페이지에서까지 확인해봤습니다.

이왕이면 구체적인 주소 및 표현까지 알려주셨더라면 좋았을 뻔했습니다.
물론 그렇다 하더라도, 아무리 Stroustrup이 C++의 창시자라고 한들
C++ 프로그램의 옳고 그름을 판단하는 절대적인 기준은 되지 못합니다.
(물론 표준화 위원회에서 활발히 활동하고 있는 Stroustrup이 표준의 해석에서 오류를 범할 가능성은 매우 낮겠습니다만.)

김일영의 이미지

제가 전달해 드리려고 하는 점은, (두 값이 다를 수 있음에도 불구하고)
b1.a와 b1.b 모두가 적법한 값들이고 저런 식으로 생성자에서 값을 저장해 두었다가
나중에 그 값으로 A, B object를 참조하는 데에 아무런 문제가 없다는 것입니다.
--> C++ 언어의 정의에서 이걸 뒷받침하는 근거를 찾으실 수 있으신가요?
저는 찾아보려고 했으나 찾지 못했습니다.
아무런 문제가 없다는 말씀은 지나친 유추가 아닐런지요?
참고로 저는 비록 b1.a가 b1.b와 다르더라도 b1외의 메모리 할당과 식별해낼 수 있는 값으로
쓸 수 있는지 여부도(예를 들면 hash table의 key로 쓰는 용도 등으로) 찾아봤습니다만,
그런 근거는 찾지 못했습니다.

아무리 Stroustrup이 C++의 창시자라고 한들
C++ 프로그램의 옳고 그름을 판단하는 절대적인 기준은 되지 못합니다.
--> 예, 일전에 인용하신 comp.lang.c++.moderated 그룹 등도 기준이 되지 못하겠지요.

김일영의 이미지

위에서 만약 x.c가 x.b와 다르다고 하면, C* 형인 x.c가 B* 형으로 형변환되는 순간
그 값도 x.b와 같은 값으로 바뀔 수 있다는 사실은 이해하고 계십니까?
--> 본인은 "쓸 수 있기는 한데, 그 값은 쓰레기값일 수도 있다"라는 얘기를 저렇게 했겠습니까?라고 하시면서, 저는 매우 우습게 보셨나 보군요.
물론 잘 알고 있습니다... 제가 이 문제로 그만큼 고생했다고 썼는데 저것도 모르고 썼겠습니까?

그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만 그 반대는 안된다는 것도 잘 이해하고 계시겠지요?
실제로 보존한 this 값을 유용하게 사용하려면 그 반대의 경우가 필요할텐데 말이죠.
애당초 this 포인터를 보존하고자 하는 경우의 문맥을 생각해 보시죠.

애초에 this 포인터를 멤버 변수에 보존하고자 하셨던 분이라면(물론 곱단오빠 님부터 해당되겠지만) "class A의 멤버 a(b라고 쓰셨지만 보기 쉽게 a라고 합시다)는 자식 클래스가 아니라 A 자체의 인스턴스에 대해서만 쓸 수 있습니다. 자식 클래스 B를 만들면 같은 식으로 b 멤버를 또 만드셔야 하고 a를 쓰면 class A의 멤버에 대해서만 쓸 수 있고요 그걸로 다른 멤버를 참조하려고 하시면 오류가 발생하고요. 자식 클래스를 만들때마다 계속 같은 식으로 멤버를 추가하셔야 합니다."라고 설명을 드렸을때 본인이 의도한 목적에 참 맞아떨어지는구나 라고 생각하시겠냐는 말씀입니다.
(아 네... 그렇다고 쓰레기값이라고 말한게 심한 표현이다고 하시면 this 포인터에게 사과하겠습니다...)

아마 그 반대를 기대하셨지 않을까요? 저의 경우엔 그랬습니다.
물론 그랬기 때문에 오류를 발견하게 됐지요.

물론 그런 방법이 musiphil님께서 의도하시는 "긍정적인" 방법이라고 하시면 굳이 반대하지 않습니다. 긍정적인 방법을 유용하게 잘 사용하시기 바랍니다.

김일영의 이미지

문제가 없으시다는 주장도 코드로 보여주시면 오해의 소지가 없을 것 같습니다.

winner의 이미지

처음에는 안된다고 했지만 자세히 보니 그럴 듯 하더군요.

만일 상속이 문제라면 상속과 함께 쓰지 않았을 경우는 괜찮은 것 아닙니까?

김일영의 이미지

winner 님께서 처음에 안된다고 하셨을때와 마찬가지로 어차피 곱단오빠님의 선택은 그분의 판단 나름입니다.
다만 전 상속 시에 문제가 생긴다는 점을 말씀드렸고 저 위에 익명으로 어떻게 시비나 걸어볼까 하는 불쌍한 인생외의 다른 분들은 무슨 말씀인지 다 이해하신 것 같으니 그것이면 소기의 목적은 됐다고 생각합니다.
상속을 받을 때 저런 문제가 있다는 점은 그리 잘 알려져 있지 않고 추후에 상속을 하지 않는다는(않아야 한다는) 것을 완벽히 예측하는 것 역시 그리 쉽지 않으니 고려할 필요는 있을 듯 합니다.

이미 중뷁입니다만 부연하자면 생성자에서 this를 얼마든지 쓸 수는 있습니다. (this->x = 1; 이런 식으로)
관련된 문헌들은 혹시 생성자 수행 전후에서 this의 값이 불안정한 것 아니냐 등의 의문에 대한 것이고 그런 문헌들은 수없이 많습니다.
그러나 그 값을 별도로 저장했다가 다른 시점에 사용하려고 하면 제가 지적한 문제를 염두에 두어야 합니다.
곱단오빠님의 의도는 후자에 바로 해당되는 경우이므로 적어도 고려하실 필요는 있겠지요.

musiphil의 이미지

김일영 wrote:
문제가 없으시다는 주장도 코드로 보여주시면 오해의 소지가 없을 것 같습니다.

문제가 없다는 것은 코드로 증명할 수 있는 성질의 것이 아닙니다.
"해 보니까 되잖아"는 그 특수한 경우(그 코드와 그 컴파일러)에 대해서만
된다는 것이지, 모든 경우에 문제가 없다는 증명은 되지 못합니다.

오히려 반례 하나만 있으면 문제가 있다는 증명은 쉽게 할 수 있습니다.
(다만 이것도 컴파일러가 완벽하다는 가정이 필요하고,
그렇지 않으면 코드의 잘못인지 컴파일러의 잘못인지 구분이 안 되긴 합니다만.)

그래서 문제가 없다는 주장은 표준에 의거할 수밖에 없고, 저도 그렇게 말씀드렸습니다.

김일영의 이미지

반례를 제시할 입장이 어느쪽인지 모르겠군요.

여하튼 제 의도는 제가 문제를 발견한 구문을 이미 짐작하셨을 것 같은데
과연 그 구문이 성립한다고 생각하셔서 그렇게 쓰신건지
아니면 그 구문에 대해 어떤 논리를 갖고 계신건지 하는 것을,
다른 분들의 의견에 먼저 반대를 제기하신 분께서 제시하셔야 하지 않냐는 것이었습니다.

먼저 반대를 제시하신 분이 뭔가 반증을 제시하셔야 하는거지
본인은 '말로' 하시면서 재반증 먼저 코드로 제시하라?
뭔가 납득하기 곤란하군요.

값 자체가 틀린 값이 된다고 하셨는데,
--> 자식 클래스의 인스턴스의 포인터와 다른 값이 '틀린 값'이라는 의미로 접수되지 않으신가 보군요.

"자식 클래스의 인스턴스를 만들 경우"라는 막연한 표현보다도
--> 이것이 막연한 표현이면 C++ 언어 학습은 너무나 버거운 일이 아닐까요?

vacancy의 이미지


필요한 경우 쓰지 않을 수 없다는 얘기는 잘못된 것 같은데요. ;;
충분히 다른 방법으로 대체가 가능할 것으로 보이는데
( 생성자 말고 다른 함수를 둘 수도 있을 거니까요. )
어떤 경우에 쓰지 않을 수 없는 것인지요 ?

그리고 이는 내 주소를 가지고 상대방이 뭘 하는지
미리 알아야 한다는 큰 문제를 가지고 있습니다.
이는 암묵적으로 캡슐화가 깨어진다고 봐야 하지 않을런지요.

경고를 내는 지는 잘 모르겠습니다만,
굳이 경고를 낸다면 이유가 있겠지요. ;;

lovewar의 이미지

class A;
class B 
{
  public:
  A *a; 
  BB(A *a);
};
 
class A {
   B b;
};
 
A::A() : b(this)
{
}

이전 코드에 추가로 코드를 기술했습니다.
위 코드와 같다고 할때, 컴파일시 경고문구가 궁금해 집니다.

익명 사용자의 이미지

질문하신 분께서 원하는 대로 쓰셔도 문제 없습니다.

#include <iostream>
 
using namespace std;
 
struct C { int ic; };
struct A;
 
struct B {
    int ib;
    A *pa;
    B(A *p) { this->pa = p; }
    void f(void);
};
 
struct A {
    int ia;
    B b;
    A() : b(this) { }
    void f(void) { cout << "A::f()" << endl; }
};
 
struct AA : C,A {
    int iaa;
    void f(void) { cout << "AA::f(), call b.f() -> "; b.f(); }
};
 
void B::f(void) { cout << "B::f(), Call pa->f() -> "; pa->f(); }
 
int main(void)
{
    AA x;
    A *pa = &x;
    C *pc = &x;
    cout << "&x = " << &x << endl;
    cout << "pa = " << pa << endl;
    cout << "pc = " << pc << endl;
    cout << "x.b.pa = " << x.b.pa << endl;
    x.f();
    return 0;
}

g++ 4.1.2 로 -Wall 옵션을 주고 컴파일했을 때 아무런 메시지도 출력되지 않습니다. 실행 결과는 다음과 같습니다.

&x = 0xbfa273c4
pa = 0xbfa273c8
pc = 0xbfa273c4
x.b.pa = 0xbfa273c8
AA::f(), call b.f() -> B::f(), Call pa->f() -> A::f()

A가 다중상속되어 AA로 쓰이고 있고, &x와 (A *)&x가 주소가 다르지만 보다시피 아무 문제 없습니다.

Quote:
그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만 그 반대는 안된다는 것도 잘 이해하고 계시겠지요?
실제로 보존한 this 값을 유용하게 사용하려면 그 반대의 경우가 필요할텐데 말이죠.
애당초 this 포인터를 보존하고자 하는 경우의 문맥을 생각해 보시죠.

이 상황에서는 this로 넘겨받아 보존한 값을 다시 원래의 타입으로 되돌릴 필요가 없습니다. B에서는 this를 클래스 A로만 다루기 때문입니다.

Quote:
애초에 this 포인터를 멤버 변수에 보존하고자 하셨던 분이라면(물론 곱단오빠 님부터 해당되겠지만) "class A의 멤버 a(b라고 쓰셨지만 보기 쉽게 a라고 합시다)는 자식 클래스가 아니라 A 자체의 인스턴스에 대해서만 쓸 수 있습니다. 자식 클래스 B를 만들면 같은 식으로 b 멤버를 또 만드셔야 하고 a를 쓰면 class A의 멤버에 대해서만 쓸 수 있고요 그걸로 다른 멤버를 참조하려고 하시면 오류가 발생하고요. 자식 클래스를 만들때마다 계속 같은 식으로 멤버를 추가하셔야 합니다."라고 설명을 드렸을때 본인이 의도한 목적에 참 맞아떨어지는구나 라고 생각하시겠냐는 말씀입니다.
(아 네... 그렇다고 쓰레기값이라고 말한게 심한 표현이다고 하시면 this 포인터에게 사과하겠습니다...)

클래스 A의 맴버 변수 b는 this를 넘겨받아 클래스 A의 형태로만 다루게 될 것이므로, 클래스 A가 상속되어 클래스 AA가 된다 하더라도 AA에 새롭게 맴버 변수를 추가할 필요는 전혀 없습니다.

Quote:
물론 그런 방법이 musiphil님께서 의도하시는 "긍정적인" 방법이라고 하시면 굳이 반대하지 않습니다. 긍정적인 방법을 유용하게 잘 사용하시기 바랍니다.

김일영님께서는 예전부터 참 말씀 험악하게 하시던데 그냥 익명 쓰시지요? 실명을 쓰는게 당당할 수 있는건 행동 또한 당당할 때 뿐입니다. 님처럼 막 말하고 함부로 사시면 그건 바로 맨얼굴로 강도질하는 셈이고, 그렇게 되면 그건 당당한게 아니라 바보짓이라고 합니다.

저는 김일영님을 ID사용자나 실명인으로 보지 않습니다. 하는 짓이 저희 익명인들과 똑같기 때문에... ㅋㅋㅋㅋ 김일영이란 이름 석자도, 실은 본인 이름이 아니라 같은 사무실에 근무하는 꼴도 보기 싫은 다른 사람 이름이 아닐까 의심스럽습니다. 고의로 먹칠을 하고 있는지 의심스럽다는 말입니다.

김일영의 이미지

이 상황에서는 this로 넘겨받아 보존한 값을 다시 원래의 타입으로 되돌릴 필요가 없습니다. B에서는 this를 클래스 A로만 다루기 때문입니다
--> "그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만 그 반대는 안된다는 것도 잘 이해하고 계시겠지요?" 라는 말이 무슨 말인지 이해가 안되는가 본데... 그러니 익명밖에 쓸 수 없다는 것은 참작해주지.

애시당초 B* p = x.c; 라는 문장을 쓴 사람은 내가 아니고 musiphil 님 이거든?
내가 하는 말은 바로 니가 한 말이야. 왜 C *형인 x.c를 B *형에 대입을 하냐고?

애당초 this 포인터를 보존하고자 하는 사람의 취지가 뭐겠어?
B *p = x.c; 이렇게 해서 p의 값을 쓰려고 했을까? 물론 아니지.

거참 머리 나쁜 너를 위해 몇 자 끄적여주마.

class A {
  A *p;
  int xA;
};
A::A() : p(this) {}
 
class B : public A {
  int xB;
}
B::B() : b(this) {}
 
B b1;

이런 코드를 만든 사람이라면 그 취지가 뭘까?
물론 요런 코드가 안된다는 것은 알고 있겠지?
"그 반대는 안된다는 것도 잘 이해하고 계시겠지요?" 라는 말은 이 말이란다.

B *pB = b1.p; // A*을 B*에 대입할 수 없으니까

그렇지만 요렇게라도 쓰고 싶었겠지? 그래서 애당초 저런 멤버를 선언했을거야 그렇지 않니?

B *pB = (B *)b1.p;
...
pB->xB = 100; // 이게 안되거든?

이제 니 독해력의 한계를 좀 알겠냐?
과연 애당초에 this 포인터를 저장하고자 했던 사람이 저걸 알았어도 그렇게 하려고 했을까?
적어도 자식 클래스를 만들게 되면 문제가 있구나 라고 생각하지 않겠냐?

클래스 A의 맴버 변수 b는 this를 넘겨받아 클래스 A의 형태로만 다루게 될 것이므로, 클래스 A가 상속되어 클래스 AA가 된다 하더라도 AA에 새롭게 맴버 변수를 추가할 필요는 전혀 없습니다.
--> 스스로 뭔가 말이 꼬이지 않나?
this를 넘겨받아 클래스 A의 형태로만 다루기 위해서 this값을 보존했다고 생각하는건 아니겠지?
그럼 클래스 AA의 멤버 변수는 어떻게 접근을 하겠다는건데? 멤버를 추가해야 하지 않니?

애당초 this값을 보존하려는 취지를 생각해보면 인스턴스를 생성하는 시점마다 포인터를 보존하는 코드를 작성하기가 곤란한 경우라는걸 알 수 있지.
그래서 인스턴스 자체의 멤버 변수에 this 포인터가 자동적으로 보존되게 해서 쓰고 싶은거지.

그러니, 위에 보여준 것처럼 쓰고 싶을게 아니겠니? 하지만 그게 안되거든.

아 물론 정말 이 방법밖에 할 수 밖에 없다든지 꼭 이 방법으로 하고 싶다면야
서브클래스를 만들때마다 멤버를 추가해서 하면 되지...
상속 받을 때마다 멤버 하나씩 추가하면 되지...
내가 굳이 그걸 말리는거 아니거든?
그래서 내가 그렇게 하면 테러하겠습니다 라고 했냐? 유용하게 잘 쓰시라고 했지 않니?
평소에 악플질이 중독되어서 좋은 말도 고깝게 들리는가 보구나. 쯧쯧

그리고 말이지, 내가 인간 취급을 안 하는건 너같이 스스로 인격을 숨기는 익명의 찌질이들에 한해서란다. 부모가 주신 이름이든, 너 스스로 니 인격에 붙인 아이디든 뭐든 밝힐 능력도 그럴 책임감도 없는 찌질이들을 내가 인격으로 대해줄 필요씩이나 있겠니? 고마 찌질이짓 청산하고 갱생이나 하려무나.

익명 사용자의 이미지

김일영님의 자학개그가 날이 갈수록 일취월장 하시는군요^^

Quote:
"그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만"

Quote:
왜 C *형인 x.c를 B *형에 대입을 하냐고?

한쪽에서는 가능하다고 하고 다른 쪽에서는 왜 해야 되냐고 묻는 이 서로 상반된 내용을 대체 어떻게 해석해야 할지... 김일영님 내부에 서로 독립된 인격이 두명 있어서 동시에 서로 다른 말을 하고 있는 것은 아닌지...

Quote:
애당초 this 포인터를 보존하고자 하는 사람의 취지가 뭐겠어?
B *p = x.c; 이렇게 해서 p의 값을 쓰려고 했을까? 물론 아니지.
거참 머리 나쁜 너를 위해 몇 자 끄적여주마.

곱단오빠님은 질문하실 때 '두 클래스가 서로 양방향으로 억세스 하기 위해서 필요했습니다'라고 말씀하셨는데, 자기 자신에 대한 포인터를 자기한테 따로 저장하는 전혀 엉뚱한 코드를 적어놓으시고 폼을 잡으시니 어이없는 표정을 지어야 되는건지 웃어야 되는건지 잠시 고민했습니다. 자기 클래스 안에서 자기 자신을 참조하고 싶으면 this 쓰면 되지 왜 굳이 따로 저장해서 쓰십니까? 김일영님의 프로그래밍 방식은 자신의 자학개그만큼이나 하이레벨이라 저같은 평범한 사람이 이해하기에는 너무나 어렵군요.

class A {
  A *p;
  int xA;
};
A::A() : p(this) {}
 
class B : public A {
  int xB;
}
B::B() : b(this) {}
 
B b1;

ㅋㅋㅋㅋ 클래스 B에 b라는 맴버 변수가 없는데 b(this)라는 초기화 목록은 대체 뭐하는 코드입니까? p의 오타라고 보기에는 키보드 사이의 거리가 너무 넓고... 손으로 썼다면 p를 b로 잘못 썼다고 우길만도 할텐데...

B *pB = (B *)b1.p;
...
pB->xB = 100; // 이게 안되거든?

아무도 그렇게 써야 한다고 한적 없는데 계속 엉뚱한 코드 꺼내서 헤메시는군요. 곱단오빠 님이 올리신 질문에서는 바로 위의 코드처럼 쓸일이 전혀 없습니다. 남들은 그렇게 써야 된다고 한사람이 한명도 없는데 왜 엉뚱한 코드를 꺼내놓고 헛소리 하시는지... 제가 한말 인용해 드리겠습니다.

Quote:
이 상황에서는 this로 넘겨받아 보존한 값을 다시 원래의 타입으로 되돌릴 필요가 없습니다.

분명히 제가 B* -> A* -> B* 할 필요가 없다고 적어 놨지요?

Quote:
this를 넘겨받아 클래스 A의 형태로만 다루기 위해서 this값을 보존했다고 생각하는건 아니겠지?
그럼 클래스 AA의 멤버 변수는 어떻게 접근을 하겠다는건데? 멤버를 추가해야 하지 않니?

상속이 뭔지 잘 모르십니까? B는 클래스 A만 사용하는 클래스인데 왜 클래스 B가 클래스 AA에서 새로 추가된 맴버 변수에 접근해야 되는지요? 클래스 B는 클래스 AA중에서 클래스 A로부터 상속받은 부분만 쓰면 되지 다른 부분은 쓸 필요가 없습니다.

자꾸 독해력 독해력 하시는데 님의 독해력이나 좀 걱정을 하시지요 ㄲㄲㄲ 그러고도 밥벌어 먹으실 수 있으시다니 우리나라 장래가 걱정됩니다 ㅉㅉㅉ

김일영의 이미지

억지개그는 점점 저질이 되는구나 ㅋㅋㅋ

"그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만"
--> 이 말을 내가 한 말이냐? 인용이라는 것이 뭔지 잘 모르면 초등학교로 가거라.
이 말은 앞서 musiphil 님 글에서
"위에서 만약 x.c가 x.b와 다르다고 하면, C* 형인 x.c가 B* 형으로 형변환되는 순간
그 값도 x.b와 같은 값으로 바뀔 수 있다는 사실은 이해하고 계십니까?"라고 한 말에 대한 답이거든?

여기서 졸지에 국어강좌를 해야 할 줄이야. 하하하.

어리석은 널 위해 다시 정리해주마.
musiphil : B *p = x.c; 가 성립하는 것을 아느냐?
나 : 물론 알고 있고, C *p = x.b; 는 안되고 C *p = (C *)x.b; 해야 대입가능한 것은 아시느냐?

이런 문장 관계란다. 아직도 국어가 힘드니? 쯧쯧.

곱단오빠님은 질문하실 때 '두 클래스가 서로 양방향으로 억세스 하기 위해서 필요했습니다'라고 말씀하셨는데
자기 클래스 안에서 자기 자신을 참조하고 싶으면 this 쓰면 되지 왜 굳이 따로 저장해서 쓰십니까?
--> 쯧쯧 스스로 니 모순을 드러내는구나.
그럼 곱단오빠 님의 이 코드는 뭐란 말이니?

A::A() : b(this)
{
}

위의 코드와 나의 이 코드에 무슨 차이가 있다는건지 니 외계어로 설명 좀 해보거라.

A::A() : p(this) {}

니 말대로면 자기 클래스 안에서 자기 자신을 참조하고 싶으면 this 쓰면 되지 왜 굳이 따로 저장해서 쓰십니까 라는 말은 내가 아니라 애당초 곱단오빠 님께 해야 할 말이겠구나?
물론 너는 그럴 생각은 없고 그저 나를 걸고 넘어질 생각 뿐이겠지.

찌질한 트집은 그만 하고 문제의 핵심을 논해야 하지 않겠니?
핵심은 this 포인터를 저장해서 나중에 쓸 때 어떤 문제가 있느냐 하는 것 아니니?
거기에 대해 지적한 문제점은 굳이 외면하고 트집 잡느라 어거지만 쓰고 있구나.

분명히 제가 B* -> A* -> B* 할 필요가 없다고 적어 놨지요?
--> 쯧쯧 여기서도 모순이 드러나는구나.
포인터라는 것 자체가 결국 어디다 써먹을까? 멤버를 참조하기 위해 쓰겠지?
그럼 앞서 내가 선언한 B 클래스에서 xB 멤버는 어떻게 접근할건데?
그러니까 정 그렇게 하고 싶으면 서브클래스마다 this 저장할 멤버 하나씩 추가하셔~ 안 말려~

분명히 니가 자기 클래스 안에서 자기 자신을 참조하고 싶으면 this 쓰면 되지 왜 굳이 따로 저장해서 쓰십니까 라고 썼는데, 그걸 보는 나는 이런 말이 절로 나오는구나.
"멤버 참조도 못할 포인터를 왜 저장하니? 애당초 그렇게 쓸 생각으로 저장했겠니?"

결론은 정상적인 국어 교육을 받으신 분은 누구나 다 이해하셨겠지만
서브클래스를 만들었을때는 저렇게 생성자에서 저장한 this 포인터 값으로
서브클래스 인스턴스의 멤버를 참조할 수는 없는 문제가 있고
그걸 면하려면 서브클래스를 만들때마다 같은 식으로 멤버를 추가해야 하니
아예 다른 방법을 찾아보는게 타당하다~ (뭐, 싫음 말고...)
이 말이 그렇게 어려웠냐? 애당초 뭐 시비걸 건덕지나 있나 찾느라 눈에 안들어왔냐?

익명 사용자의 이미지

Quote:
그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만"--> 이 말을 내가 한 말이냐?

이분 왜 자꾸 헛소리를 하실까 ㅉㅉㅉ

http://kldp.org/node/85645#comment-407708

Quote:
그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만 그 반대는 안된다는 것도 잘 이해하고 계시겠지요?

저기 위에 김일영 님하고 여기 아래 김일영 님하고는 동명이인이신가요? ㅋㅋㅋㅋ

Quote:
그럼 곱단오빠 님의 이 코드는 뭐란 말이니?

A::A() : b(this) { }

김일영님 여기서 가진 밑천 진짜 있는대로 털리시네요^^ 위에 곱단오빠님께서 질문하신 코드에는 b의 타입이 클래스 B인데 비해서 님이 적으신 코드는 p의 타입이 A*지요. 매개변수로 this를 주고 B의 생성자 함수를 호출하는거하고, 클래스 A에 대한 포인터에 this를 저장하는 거하고 어찌 같은 경우라 할 수가 있나요? ㅋㅋㅋㅋ

Quote:
포인터라는 것 자체가 결국 어디다 써먹을까? 멤버를 참조하기 위해 쓰겠지?
그럼 앞서 내가 선언한 B 클래스에서 xB 멤버는 어떻게 접근할건데?
그러니까 정 그렇게 하고 싶으면 서브클래스마다 this 저장할 멤버 하나씩 추가하셔~ 안 말려~

그러니까 님의 코드가 개그라 이말입니다. 질문하신 분께서는 서로 다른 클래스끼리 상호 참조하는 경우를 물으셨는데 님의 코드는 B가 A를 상속하게 만들어서 B에서 this를 자기자신의 A*형 포인터 맴버 변수인 p에 저장하게 해서 p를 통해 B형 클래스의 맴버 변수인 xB에 접근하려 드니 이거 무슨 근친상간도 아니고 웬 삽질이랍니까?

님이 만든 엉터리 코드 기준으로 말씀하시면 당연히 말이 안되고요, 제가 위에 적은 예제 코드 기준으로 말을 하자면, 클래스 B가 넘겨받은 this 값을 통해서 클래스 AA의 iaa에 접근할 수 없는건 당연하고, 또한 접근할 이유 자체가 없지요.

Quote:
핵심은 this 포인터를 저장해서 나중에 쓸 때 어떤 문제가 있느냐 하는 것 아니니?

좀 더 정확히 말하자면, '클래스 A의 생성자 함수의 초기화 리스트에서, 클래스 A의 맴버 변수인 클래스 B에다가 B의 생성자 함수를 바로 호출해서 클래스 A의 포인터 주소 값인 this를 넘겨 주는 것이 어떤 문제가 있는가' 가 되겠지요?

이에 대한 답은 위에 musiphil님과 아래 체스맨 님이 밝혀주신 대로, '클래스 B의 생성자 함수 안에서 클래스 A의 맴버 함수를 호출하거나 맴버 변수를 참조하는 행위만 하지 않고, 여기서는 단지 주소값만 저장해둔 다음에, 나중에 클래스 A의 생성자 함수가 끝나고 클래스 A가 생성된 다음에 클래스 A의 맴버 함수나 변수를 이용하면 아무 문제가 없다' 입니다. 문제가 생길 때는 클래스 A의 인스턴스가 아직 완전히 생성되기 전에 클래스 B에서 클래스A의 맴버 함수나 변수를 사용했을 때 뿐입니다. 아래 체스맨님이 보여주신 MSDN 인용문도 바로 이걸 설명하고 있는 것이죠.

Quote:
분명히 제가 B* -> A* -> B* 할 필요가 없다고 적어 놨지요?
--> 쯧쯧 여기서도 모순이 드러나는구나.
포인터라는 것 자체가 결국 어디다 써먹을까? 멤버를 참조하기 위해 쓰겠지?
그럼 앞서 내가 선언한 B 클래스에서 xB 멤버는 어떻게 접근할건데?
그러니까 정 그렇게 하고 싶으면 서브클래스마다 this 저장할 멤버 하나씩 추가하셔~ 안 말려~

님께서 상속의 개념이 전혀 없으시니 설명하기가 참으로 막막합니다. AA가 A를 상속받고, B가 A를 참조해서 쓸때, B 쪽에서 AA에 새로 추가된 부분에 접근할 이유는 전혀 없지요. 근데 왜 님은 자꾸 B에서 AA에 새로 추가된 iaa에 접근해야 된다고 말씀 하시는지... 님의 엉터리 코드는 제발 좀 집어치우고 말씀하시지요.

Quote:
결론은 정상적인 국어 교육을 받으신 분은 누구나 다 이해하셨겠지만
서브클래스를 만들었을때는 저렇게 생성자에서 저장한 this 포인터 값으로
서브클래스 인스턴스의 멤버를 참조할 수는 없는 문제가 있고

질문자가 올리신 코드에서는 클래스 B가 클래스 A에 대해서만 건드리도록 되어 있는데 자기 혼자 엉터리 코드 올려놓고서는 남들이 원하지도 않는 이상한 상황을 가정해서 그건 안된다고 핏대를 세우네요. 클래스 B에서 대체 왜 클래스 A의 자식들의 상속받지 않은 부분에 대해서 접근을 시도해야 한답니까?

이 쓰레드에서 님을 제외한 단 한명도 서브 클래스 인스턴스의 상속받지 않은 부분에 대해서 접근해야 된다고 말한 사람이 없는데 혼자 말하고 혼자 답하네요. 대체 누구하고 대화를 하시고 계십니까? 님의 눈에는 다른 사람의 눈에는 보이지 않는 투명한 글이 하나 더 보이시는가요?

김일영의 이미지

그러면 C *형인 x.c를 B *형에는 명시적인 형변환 없이 대입가능하지만"--> 이 말을 내가 한 말이냐?
--> 이 부분은 니가 그 다음줄을 읽는 순간 쪽팔려질테니 더 논하지도 않겠다. 쯧쯧

위에 곱단오빠님께서 질문하신 코드에는 b의 타입이 클래스 B인데 비해서 님이 적으신 코드는 p의 타입이 A*지요.
--> 물론 그건 알지~! 그런데 곱단오빠 님의 코드에는 class B 선언이 없거든?
그러면 설마하니 곱단오빠 님께서 이런 코드를 생각하고 썼을 것 같으냐?

class B { int x; }; // A랑 아무 상관 없어~
class A { B b; };
A::A() : b(this)
{
}

니 생각엔 이렇게 짰을 것 같으냐?
당연히 B와 A 간에 상속 관계가 있겠지... 대입가능하니까 저렇게 하려고 했을 것 아니시겠어?
이제 니 단세포가 좀 느껴지냐?
익명 사용자의 이미지

Quote:
당연히 B와 A 간에 상속 관계가 있겠지... 대입가능하니까 저렇게 하려고 했을 것 아니시겠어?

ㅋㅋㅋ 뒤집어 지겠군요. 오히려 자기 자신이 독해력에 문제가 있음을 스스로 증명하시다니. 제가 혹시라도 못 보실까봐 굵은 글씨로 강조하시니 감사할 따름입니다.

http://kldp.org/node/85645#comment-404890

Quote:
두 클래스가 서로 양방향으로 억세스 하기 위해서 필요했습니다.

곱단오빠님께서는 두 클래스가 서로 양방향으로 억세스 하기 위해서 필요했다는데 웬 있지도 않은 상속관계? ㅋㅋㅋ

김일영의 이미지

우선 나도 말꼬리 한번 잡아주마.

제가 혹시라도 못 보실까봐
--> 스스로를 높여주는 싸가지. 역시 국어 교육이 필요하겠군?

어쨌든, 그러면 너는 곱단오빠 님이 역시 이렇게 썼을 거라고 생각하는거냐?

class B { int x; }; // A랑 아무 상관 없어~
class A { B b; };
A::A() : b(this)
{
}

나한테 시비하기 전에... 그럼 곱단오빠님의 소스를 가지고 컴파일이나 한번 해보렴...
아님 니가 생각한 코드를 컴파일 해보든지... 무뇌아처럼 아무 생각도 안해보고 내뱉지 말라구. 오케?
익명 사용자의 이미지

http://kldp.org/node/85645#comment-407724

님같이 직접 돌아가는거 안보면 안믿는 분을 위해서 위에 이미 돌려보고 결과까지 올렸답니다^^

님이 상속 어쩌고 해서 A가 아니라 A로부터 상속받은 AA로 돌아가는 것까지 이미 보여드렸습니다 ㅋ

대체 남의 글은 읽어보고 떠드는 건가여? ㅋㅋㅋㅋ

체스맨의 이미지

문법상 문제 없습니다. 김일영님 말씀처럼 this 값 자체가 잘못 넘어가는 경우는 없습니다. this 의 멤버를 참조하게 되는 경우만 문제가 됩니다. 이것은 구현하는 사람의 책임이 되죠.

위 익명분 말씀처럼 gcc 는 -Wall 옵션에서 경고를 내지 않습니다.
이 경고는 비쥬얼 C++ 컴파일러에서 나는 오류이고 경고문입니다. 적법하지 않다면 오류가 나야 마땅하지, 경고를 낼 수는 없는 겁니다.

warning C4355: 'this' : used in base member initializer list

MSDN 에 C4355 에 대해 다음과 같이 서술합니다.

The base-class constructors and class member constructors are called before this constructor. In effect, you've passed a pointer to an unconstructed object to another constructor. If those other constructors access any members or call member functions on this, the result will be undefined. You should not use the this pointer until all construction has completed.

다음 부분때문에 경고문을 낸다는 얘깁니다.
"If those other constructors access any members or call member functions on this"
그래서 위와 같은 코드를 작성하지 않는다면 전혀 문제될 것은 없습니다. 하지만, 좋은 방법이라고 말씀 드릴 수는 없습니다.

Orion Project : http://orionids.org

김일영의 이미지

보존해놓은 포인터값을 가지고 멤버를 참조하려고 할 때 어떤 멤버를 참조하느냐에 따라 오류가 납니다... (사실 오류가 안 나는 멤버 참조의 경우에도 그것이 C++ 표준에서 보장된다는 말은 없고 말이죠) 이런걸 쓰레기값이라고 하지 않나요? 포인터를 가지고 멤버를 참조하려고 할 때 오류가 나는 포인터값이 적법한 포인터값인가요? 위에 글 쭉 보시면 아시겠지만 계속 같은 말 하고 있는 겁니다.

체스맨의 이미지

그것은 생성자에서 넘어온 this 가 쓰레기값임을 의미하는 게 아닙니다.

제가 참조해드린 MSDN 에 이렇게 돼 있지요?

You should not use the this pointer until all construction has completed.

여기서 'use' 의 정의는 멤버를 참조할 때를 의미합니다.

생성자가 완전히 작동하기 전까지만 그런 참조를 하지 않으면 됩니다. 즉, 생성자에서 넘어온 this 포인터를 단순히 저장해놓고, 생성자에서 그 멤버를 참조하지 않으면 아무 문제가 없습니다.

C 코드로 예를 들어보면

struct _my_struct* this = malloc( sizeof(struct _my_struct) );

생성자로 넘어간 this는 위와 같은 상태로 볼 수 있습니다. ( this 에 할당된 메모리에 저장된 값들은 쓰레기값 맞습니다. 이 부분을 인정하지 않는 게 아닙니다.
this 포인터값 자체는 쓰레기값이 아니기 때문에, 이 값을 단지 저장만 해놓는 것은 아무 문제가 되지 않는다는 것을 말하려는 것입니다. 이 것이 오해되는 부분이 아닌가 싶군요. )

그런데, 다음과 같은 함수가 있다고 하면,

int
my_function( struct _my_struct* this )
{
    return this->a + this->b;
}

this 를 넘겨받은 생성자에서 이 함수를 호출한다면, 멤버 a, b가 초기화되기 전일 수 있기 때문에 결과는 undefined 입니다. MSDN 에서 지적하는 바는 그것입니다. this 포인터의 값 자체는 생성자든, 그 이후든 변하지 않기 때문에 단순히 this 를 저장해놓는 것은 아무런 문제가 없는 구현입니다.

이것이 gcc 에서는 -Wall 에서도 아무 문제 없이 컴파일되는 이유입니다. 왜 gcc 에서는 아무 문제 없이 컴파일 된다고 생각하시나요?

참고로, VC++ 의 최대 경고레벨에서 경고문들은, VC++ 에서 배포하는 자체 헤더 파일에서도 경고를 발생할 정도로 극악 스럽습니다.

구글에서 저 경고문을 검색어로 찾을 수 있는 관련 답변들도 확인해 보세요.몇개 링크해봅니다.

http://www.thescripts.com/forum/thread264514.html
http://www.devmaster.net/forums/showthread.php?t=2277

Orion Project : http://orionids.org

김일영의 이미지

일단 서브클래스의 멤버를 저 포인터로 접근할 수는 없다는 점은 익명의 찌질이만 빼고는
이제 다들 아실 줄로 생각됩니다.

"쓰레기값"이라는 용어에 대한 논의에 국한해서 설명드리겠습니다.

일단 누누히 말씀드렸다시피,
생성자에서 this 값을 어디다 저장하는 문장 자체가 잘못됐다는 말은 아닙니다.
(같은 설명을 여러번 하려니...)

일단 제가 "쓰레기값"이라는 용어를 썼을때는 서브클래스의 멤버에 접근할 수가 없다는 점에서
당초 이런 코드를 작성하시는 분들이 의도했음직한 것과는 다른 것이기 때문에 그렇게 말씀드린겁니다.

그러나, 그것만이 아니고 이슈가 더 있습니다.
제가 서브클래스와 관련된 문제를 겪었을때 생각했던 것이 하나 더 있는데, 이런 겁니다.
"이 값으로 서브클래스(B)의 멤버를 참조할 수는 없다는 것은 알았어.
그렇지만 이 값으로 부모클래스(A)에서 상속된 멤버를 참조하는 것은
C++ Standard에서 보장하는걸까?
그것도 아니라면 이 값이 '유효하지도 않은' 값이라 하더라도
Hash table 키 같은 용도로는 쓸 수 있는,
그러니까 C++ Standard에서 '유일성은 보장되는' 그런 것일까?"

이런 고민을 해서 찾아봤지만, 적어도 제게는 그렇게 해석되는 부분은 찾을 수 없었다는 것입니다.

musiphil 님은
"b1.a와 b1.b 모두가 적법한 값들이고"
"저런 식으로 생성자에서 값을 저장해 두었다가
나중에 그 값으로 A, B object를 참조하는 데에 아무런 문제가 없다"
고 말씀하시지만
저로서는 이미 그때 찾아봤지만 그런 근거를 찾을 수는 없었다는 것입니다.

만약 "부모클래스(A)에서 상속된 멤버를 참조하는 것"도
C++ Standard에서 보장하는 것도 아니고,
C++ Standard에서 '유일성을 보장'하지도 않는다면,
이건 글자 그대로 "쓰레기값"이라고 해야 마땅할 것 같습니다.

즉, 다시 부연 부연하자면
생성자에서 this 값을 어디다 저장하는 문장 자체가 잘못됐다는 말이 아니고,

X *pX = new X; // 이 문장은 당연히 정상입니다.
delete pX;
pX->abc = 123; // 그러나 보존해둔 this값은, 마치 여기서의 pX와 같은 상태가 됩니다.

이런 의미입니다.
체스맨의 이미지

다음과 같은 의미라고 하셨는데,

X *pX = new X; // 이 문장은 당연히 정상입니다.
delete pX;
pX->abc = 123; // 그러나 보존해둔 this값은, 마치 여기서의 pX와 같은 상태가 됩니다.

이건 아닙니다. 무엇을 근거로 그렇게 생각하시는지요?

지금 논의되는 상황의 this 포인터는
1. 할당은 된 상태이지만,
2. 완전히 초기화되지는 않은 상태입니다.

그러므로, delete 된 상태와 같다고 볼 수 없습니다.

이 문제의 논점은 2번, 즉 완전히 초기화 되지는 않은 상태라는 것일 뿐입니다.

Orion Project : http://orionids.org

김일영의 이미지

지금 애당초 곱단오빠 님이 올린 문제가 말씀하시는 그 문제라고 생각하세요?

아휴~ 하도 하도 갑갑해서 제가 코드로 비유를 했더니 그걸 문제삼으시는군요.
곱단오빠 님이 올린 문제가 생성자 안에서 this 를 쓰는 것에 대한 문제냐구요...

그게 아니지 않습니까... 제가 말하는건 this 포인터를 저장해놓는 것엔 하자가 없지만
서브클래스에 대해서 쓸 때는 우선 그 서브클래스에 추가된 멤버에 대한 참조도 안되거니와
원래 부모클래스에서 상속된 멤버에 대해서 참조가 된다고 하더라도
C++ Standard에서 보장된 것이 아니기 때문에 - 제가 조사했던 바로는 -
결국 illegal하다... 그러니까 "쓰레기값"이다... 마치 delete 시킨 개체에 대한 포인터와 같다...

이 말이 그렇게 어려운 말인가요...

지금 말씀하시는건 생성자 중에서 this 에 접근할 때 undefined 될 수 있는 경우를 예시하신거지
이 문제는 그게 아니지 않습니까...

누누누누누누히 말씀드립니다마는 제가 제기한 문제는 생성자하고는 아무아무아무 관련도 없는
하~~~~~~안참 후에 그 저장해놓은 값을 써먹으려고 할 때 생기는 문제를 말한 것입니다....

체스맨의 이미지

코드는 분명히 잘못됐습니다. 잘못된 것을 지적하는 것이 곡해입니까?
답답하면 정당한 주장을 해야지 잘못된 코드를 예시하면 안되지요.

오히려 김일영님께서 곱단오빠님의 원 주제를 확대해석하시는것 같군요.
위에 링크한 구글에서 찾은 동일한 문제에 대한 답변들을 살펴보시기 바랍니다. 이 문제에 대한 답변은 애초에 이렇게 논의를 길게할 필요가 없는 것입니다.

김일영님께서 무엇을 지적하시는지 알 것 같지만, 말씀하신 서브클래스에 대해서 사용하는 것은 지금 원주제와 관계가 없습니다.

원주제는 초기화리스트에 this 를 넘겼는데 경고가 나더라, 왠일이냐 하는 문제고, 이 부분에 대해 경고를 내는 드문 컴파일러중 하나인 VC++ 의 MSDN 에서 제시한 근거에는 김일영님께서 주장하는 내용은 전혀 없습니다.

Orion Project : http://orionids.org

김일영의 이미지

참... 설마 그 코드를 이 문제에 대한 핵심이라고 올렸을까요...
물론 글이 길어서 본인 쓰레드도 아닌데 보시기 불편하셨을지 몰라도
저 위에 다 몇번이고 코드도 올리고 한 것이 있는데 그러네요...

VC++ 의 MSDN 에서 제시한 근거에는 김일영님께서 주장하는 내용은 전혀 없습니다.
--> 당연하죠... C++ Standard에 이런게 있더라 하고 나오지 이런건 없다 라고 나오겠습니까?
제가 말하는건 C++ Standard에 규정이 안되어 있으니까 illegal하다는 것입니다.

원주제 원주제 하시는데... 원주제는 왜 warning이 나오냐에 대한 문법적 질문이 아니고요...
과연 이런 식으로 멤버를 사용하는게 무슨 문제 가능성이 있길래 그러냐는 말씀인줄 알고요...
저는 제 경험도 있었고 하니 서브클래스에서 쓰면 요런 문제가 생길 수 있습니다...
그러니깐 가급적 쓰지 마십시오~ 라고 한겁니다...

여하튼 말씀하신 바는 저 역시 잘 알겠습니다. 덕분에 공부도 되는군요...

체스맨의 이미지

한참 후라는 것은 매우 모호한 말입니다.

this 를 넘기고 그 this를 저장해놨는데,
그 this 에 해당하는 포인터를 어느 순간에 지웠다면 (delete)
this 를 저장하고 있던 클래스가 그 포인터를 사용하는 순간 그것은 잘못된 접근이 당연히 일어나지요. 이것을 말씀하시는 것 같습니다. 그런데 이건 아주 당연한 일입니다. 위에 분들이 이걸 모르고 말씀하신 것 역시 아닙니다.

이건 아주 당연한 일이지만, 이러한 문제를 방치했다면 그것은 개발자의 책임일 뿐이지, 문법상 오류를 얘기할 수 없습니다.

cross 레퍼런스를 둘때 위와같은 경우가 발생한다면 this 를 저장하고 있던 측에, 죽기 전에 나 지금 죽는다고 통보하는 callback 을 사용합니다.

이건 개발자의 책임이고 디자인 문제입니다.

Orion Project : http://orionids.org

김일영의 이미지

아직 제 글을 제대로 이해를 못하신 것 같네요...
서브클래스의 인스턴스에 대해서는 그 저장해둔 포인터값이 타당하지 않다... 그거 아닙니까?
그 인스턴스를 delete 했다는 말이 아니고요.
그리고 언제 문법상 오류라고 했나요?

무슨 말인지 제대로 이해하신 후에 다시 댓글을 올리시던가 했으면 합니다.
왜 뜬금없는 Callback 이야기는 자꾸 하시나 했더니...

체스맨의 이미지

서브 클래스 인스턴스에 대해서는 저장해둔 포인터값이 타당하지 않다는 것은

class B : public A {
int x;
};

관계이고

A a;
B* b = (B*)&a;
b->x = 1234; <--- 이게 타당하지 않다는 것을 의미하는 것 맞죠?

이건 당연히 타당하지 않습니다만,
이런 용도를 예시하는게 지금 다루는 문제와 관계가 있습니까?

정확히 무엇을 주장하는지가 확실치 않군요.

Orion Project : http://orionids.org

김일영의 이미지

그런 문제가 있으니까 가급적 쓰지 말라고요... 우리말이 그렇게 어렵게 느껴지신다면 그게 제 탓은 아닌 것 같습니다.

익명 사용자의 이미지

Quote:
일단 서브클래스의 멤버를 저 포인터로 접근할 수는 없다는 점은 익명의 찌질이만 빼고는
이제 다들 아실 줄로 생각됩니다.

익명의 찌질이입니다^^/

대체 제가 언제 서브클래스의 맴버를 저 포인터로 접근해야 된다고 말했습니까? 제가 쓴 내용 다시 보여드릴까요?

Quote:
B에서는 this를 클래스 A로만 다루기 때문입니다.
...
클래스 A의 맴버 변수 b는 this를 넘겨받아 클래스 A의 형태로만 다루게 될 것이므로, 클래스 A가 상속되어 클래스 AA가 된다 하더라도 AA에 새롭게 맴버 변수를 추가할 필요는 전혀 없습니다.
...
B는 클래스 A만 사용하는 클래스인데 왜 클래스 B가 클래스 AA에서 새로 추가된 맴버 변수에 접근해야 되는지요?

지금까지 서브클래스의 맴버에 접근해야 된다고 우긴건 님뿐이었는데요?

제가 언제 서브클래스의 맴버에 접근해야 된다고 말했는지 좀 인용이라도 해 보시죠.

아참, 위에 다른 익명분하고 헷갈릴까봐 미리 밝혀두지만 제가 최초로 이 쓰레드에서 쓴 글은 이겁니다.

Submitted by 익명 사용자 (미확인) on 금, 2007/09/07 - 9:46pm.

김일영의 이미지

지금까지 서브클래스의 맴버에 접근해야 된다고 우긴건 님뿐이었는데요?
--> 여기에 대해서 내가 한 말은
"서브클래스의 멤버에 대해서는 접근하지도 못할 놈의 포인터를 저장하려고 했겠냐?"라는
당연백배한 의문이었다.

네가 만약 주유소 알바라면 대형 트럭이 와서 기름 넣어달라는데 휘발유 만땅 채워주고
"휘발유 엔진이면 잘 돌아가요."라고 할 놈이로구나.

용하다.

익명 사용자의 이미지

그럼 제가 하지도 않은 말을 가지고 했다고 님이 우기신건 사실이라고 인정하시는 셈이신가요? ㅋㅋㅋ 남이 하지도 않은 말을 억지로 꾸며서 매도하진 마시죠. 이 쓰레드 읽는 사람들이 무슨 붕어도 아니고 님의 그런 어설픈 술책에 당할꺼 같습니까? 님의 정직하지 못하고 교활한 태도나 드러날 뿐입니다.

게다가 서브클래스의 맴버에 대해서 접근을 못하는건 아니죠. 서브클래스의 맴버중 부모로부터 상속받지 않은 부분에 대해서 접근을 못하는 겁니다.

그리고 서브클래스의 맴버 중에 부모로부터 상속받지 않은 부분에 대해서 접근을 못한다고 해서 질문자가 올린 대로 초기화 리스트에 this 적고 주소를 건네는 방식이 불가능한 것은 아닙니다. 이미 제가 가능한 예제 코드를 위에 적어놨을 텐데요.

반박하고 싶으시면 제가 위에 올린 소스가 뭐가 문제인지 한번 말씀해 보시죠 ㅉㅉㅉ

김일영의 이미지

그럼 제가 하지도 않은 말을 가지고 했다고 님이 우기신건 사실이라고 인정하시는 셈이신가요?
--> 언제? 내가 하지 않은 말을 니가 우긴 적은 있을지 몰라도...?
내가 남이 무슨 말 했다고 우긴 적이 어디 있는데?

게다가 서브클래스의 맴버에 대해서 접근을 못하는건 아니죠. 서브클래스의 맴버중 부모로부터 상속받지 않은 부분에 대해서 접근을 못하는 겁니다.
--> 아그야!!!
그것도 C++ Standard 차원에서 그걸 보증해주는 문구는 찾을 길이 없었노라고 썼거든?
물론 딴지거느라 바빠 다른 분과의 쓰레드는 볼 길이 없었음을 익히 이해한다만,
더불어 그런 문제도 있다는걸 알아두거라...

반박하고 싶으시면 제가 위에 올린 소스가 뭐가 문제인지 한번 말씀해 보시죠 ㅉㅉㅉ
--> 쯧쯧... 인생아...
"제가"라는 말을 쓰려면 니 아이디로 로그인이라도 해야 하지 않겠니?
개나 소나 다 익명인데 니가 누군데? 왜 달리 익명이라고 하는지 모르니?
니가 인격으로 인정받고 싶으면 익명으로 써서 구별이 안돼도 알아모셔야 하고
남을 깔때는 익명이라 신났다 그지? 에라 인간아

체스맨의 이미지

오해가 아닌가 합니다. 정리해보면,

1. 초기화 리스트에서 생성자에 this 를 넘기고, 그 생성자에서 this 값을 저장해두는 것은 아무 문제가 없습니다.

2. 하지만, 초기화 리스트에서 생성자로 넘어온 this 포인터의 멤버나 메소드를 참조하는 것은 문제가 있습니다. 이 구현은 프로그래머의 책임입니다.

김일영님께서, 2번만 주장하신다면 그것은 맞는 말이고, 저는 2번이 문제가 없다라고 한 적이 없고 다른 분들도 그런 것으로 보이며, 위의 논의는 오해입니다.

만일 2 때문에 1이 안된다고 주장하신다면, 저나 다른 분들이 말씀하신 내용도 확인해보셨으면 합니다.

Orion Project : http://orionids.org

체스맨의 이미지

참고로 경고문이 거슬리시면 다음과 같은 코드를 사용하세요.

#ifdef _MSC_VER
#pragma warning(disable:4355)
#endif

Orion Project : http://orionids.org

popopome의 이미지

조심하면 가능하고 훌륭한 방법이긴 하지만
누군가에게 이 내용을 설명해야하고, 어떤 위험인지 알려야하잖아요.
(스토리가 길어지죠. 물론 설명하면서 어떤 심리적인 보상감도 가질 수는 있겠지만...)

가능한 이런 문제의 소지가 많은 표현은 자제하고
좀 테크닉은 없지만 다른 간단한 방법(init과 같은)으로
접근하면 어떨까요?

익명 사용자의 이미지

C++을 잘 아는 프로그래머가 생각보다 드뭅니다.
프로그래머로서는 C++을 사랑하지만
관리자로서는 C++은 악몽 그 자체입니다.

daybreak의 이미지

여기 키보드 워리어 한 명 추가요.

체스맨의 이미지

김일영님, 하나만 물어보죠.

class A {
    int value;
    B b;
    A : b(this) { this->value = 1234; }
};

김일영님께서는 A 의 멤버 b 로 전달된 this 와, A 의 생성자 구현에서 사용된 this ( this->value = 1234 ) 두 포인터가 다른 값을 가질 수 있다는 것을 주장하는 것입니까?

만일 그렇게 생각하신다면 그것은 잘못된 생각이라 말씀드리는 것이고, 이 상황에서 경고문을 내는 MSDN 에서도 그런 주장은 하지 않습니다. 만일 김일영님의 주장대로라면, 이 상황은 절대로 경고문일 수 없습니다. error 가 되어야 하지요.

하지만 g++ 컴파일러는, this 값을 넘기는 자체에 대해서는 아예 문제가 있는 것으로 취급하지 않습니다. 이 부분도 고려하시기 바랍니다.

Orion Project : http://orionids.org

김일영의 이미지

저는 위에도 쓰고 또 쓰고 또 씁니다만...
생성자 안에서의 어떤 상황을 말씀드리는게 저어어어어어얼대 아닙니다...

이제 웬만큼 제 주장을 설명하는 코드도 다 썼고... 그거 보시면 금새 아실텐데
왜 자꾸 제가 한 말과는 전혀어어어어어 상관 없는걸 가지고 말씀하시나요...

일단 제가 문제가 있다고 한 부분은 서브클래스의 인스턴스를 만들고,
나중에 b에 저장된 포인터 값으로 멤버를 참조하려고 할 때!
그때 당초 의도했던 것과 다를 거라는 것,
그리고 일부 멤버가 참조가 되더라도 C++ Standard가 보장하는게 아니라는 것,
그런 것입니다.

위에서도 계속 쓰고 있는데 왜 그러시나요...

체스맨의 이미지

말씀하신 경우는 원질문에 대한 직접적인 답변이 못됩니다.

cross refernce 가 제거될 때 필요한 처리 (callback 등)을 하는 것은 개발자의 의무일 뿐입니다.

초기화 리스트에서 this 를 넘겨도 되냐 안되냐와는 다른 문제입니다.
제가 보기엔 김일영님께서 원주제에서 제기된 코드가 야기할 수 있는 하나의 문제점을 제시하는 과정에서 논의가 꼬인 거라 생각됩니다만,

어떤 구현이 차후에 만들어낼 수 있는 문제점은 항상 존재할 수 있지만, 그렇다고 해서 그 구현 자체가 잘못된 것으로 단정할 수는 없는 것입니다.

Orion Project : http://orionids.org

김일영의 이미지

어떤 구현이 차후에 만들어낼 수 있는 문제점은 항상 존재할 수 있지만
--> 예, 맞습니다...
애당초 곱단오빠 님께서 물어보신건 "도대체 이렇게 쓰면 무슨 문제가 있냐?" 이것 아니었는지요?
그래서 제가 그중에 유력한 문제를 하나 예를 들어드린 것 뿐입니다.

그렇다고 해서 그 구현 자체가 잘못된 것으로 단정할 수는 없는 것입니다.
--> 예, 역시 맞습니다...
제가 생성자에서 this를 저장하는 것이 C++ 표준에 위배된다고 한 적은 없습니다...
단지 문제가 있다고 한 것 뿐입니다...

체스맨의 이미지

김일영님께서는, 위와같은 코드를 작성함으로써 발생 가능한 문제점을 제시한 것이라 생각됩니다.

우선 원문의 코드 '자체'에는 아무 문제가 없고 이 부분은 김일영님도 동의 하신 것입니다.

하지만,

첫째로, 김일영님이 그것을 하는 과정에서 그런 문제점을 제시하는 것임을 명확히하지 못했기 때문에 논의가 왜곡되고 길어진 것 같습니다.

둘째로, 상호 참조를 두게 되면 한쪽이 먼저 제거된 후에 다른쪽에서 그것을 접근할 수 있는 경우 분명히 문제가 발생하는 것은 당연한 것이고, 김일영님께서는 이 문제를 지적한 것으로 보입니다. 하지만, 이런 문제는 곱단오빠님이 제시한 코드가아니라, 'cross pointer 를 갖는 모든 자료구조가 갖는 문제점'입니다. 이 부분이 제가 확대 해석됐다고 말씀드린 부분입니다.

위와 같은 문제는 항상 개발자가 염두에 두어야 하고 프로그램의 특성과 상황에 따라 구현을 결정할 문제입니다.

Orion Project : http://orionids.org

김일영의 이미지

말씀하신게 맞는 말씀입니다만 저는 상호 참조 이야기를 한 것은 아닙니다.
사실 그 부분은 제가 잘못 아는건지 모르겠습니다만
부모클래스 초기화에서의 this 값과 서브클래스 인스턴스 참조 간의 문제를
상호 참조 관계의 문제라고 생각해보지도 못했습니다.

김일영님이 그것을 하는 과정에서 그런 문제점을 제시하는 것임을 명확히하지 못했기 때문에
라고 하신 부분은 좀 황당합니다. 처음에 답하신 분들 다 저처럼 쓰시지 않으셨나요?
제 글이 길어진 것은 musiphil 님 글에 댓글을 단 사람이 저여서 그런거지
굳이 처음에 제 글이 무슨 문제가 있어서라곤 생각이 안되는군요.

체스맨의 이미지

윗 글들을 다시 살폈습니다. 다른 분들의 처음 답변은 곱단오빠님이 제시한 문제에 대한 직접적인 답변이었고, 김일영님은 그렇지 않은 것 같은데요...

혹시 이 부분을 잘못생각하고 계시지 않나 여겨지는군요.

class A {
    X x;
    A : x(this) {};
};
 
class B : public A {
}

김일영님께서는 B 의 인스턴스를 만들면 A 생성자의 초기화 리스트에 적혀있는 x(this) 구문에 A 의 this 가 넘어가서 문제라는 걸 주장하시나요?

만일 그거라면 그 주장은 잘못된 것입니다.

우선 x(this) 에서 A 의 this 가 넘어가는 것은 맞는데,
이게 문제를 일으키는 것은 아무것도 없습니다.

왜냐면 개체 x 는 A 의 this 로 알고 받으니까요. 만일 거기에서 억지로 B* 캐스트한다는 건 말이 안됩니다. 이건 C++ 을 잘 못 사용하는 것이죠.

단, 말씀드렸듯이 초기화가 덜 된 문제는 남아 있습니다. 그래서 멤버를 접근하면 안됩니다.

Orion Project : http://orionids.org

김일영의 이미지

제가 거기서 x에 this가 대입이 안된다고 했나요?
지금까지 한 5번은 되풀이한 것 같습니다. 재미있나요?

나중에 그걸 B 인스턴스에 쓰려고 하면 문제가 된다는 겁니다.
이건 C++ 을 잘 못 사용하는 것이죠.
--> 예, 그러니까 잘 못 사용하는 거라고요.
그런데 애당초 this를 보존하려는 생각을 했을때는 그렇게 생각할 가능성이 꽤 있거든요.
저 뿐 아니라 남의 소스를 볼 때도 가끔 봤으니까요. 그래서 되는 줄 알고 하다가 문제를 발견한거고요.
이젠 시원하십니까? 이해가 되십니까?

체스맨의 이미지

끝가지 무엇을 주장하고 싶으신가요?

C++ 의 그러한 잘 못된 사용예는 지금 제시된 문제와 아무런 관계가 없습니다.
남의 소스 볼때 보신 건 C++ 을 잘 모르고 잘 못 작성한 코드에 불과합니다.

this 를 보존하려는 생각을 할 때에 김일영님과 같은 생각을 가지고 하는 것은, 일반적인 생각이 아니라는 것을 말씀드리고 싶군요.

Orion Project : http://orionids.org

김일영의 이미지

this 를 보존하려는 생각을 할 때에 김일영님과 같은 생각을 가지고 하는 것은, 일반적인 생각이 아니라는 것을 말씀드리고 싶군요.
--> 글쎄 저는 그런 생각을 할 가능성이 있다고 생각해서 글을 썼는데,
체스맨님께 확인받고 올려야 하는 거였군요. 미안하지만 본인 홈페이지에서 그렇게 하시기 바랍니다.

그러면 this를 보존하려는 생각을 할 때 체스맨님은 어떤 생각을 하시는지
여기서 다들 그렇게 애타게 외치는 코드로 좀 작성해주시면 큰 가르침이 될 듯 합니다.

체스맨의 이미지

제가 하지 않은 말을 꾸며내시진 마시죠.
제가 언제 확인 받으라 했나요?
토론의 기본 자세는 잃지 않으셨으면 합니다.

this 를 참조하는 경우에 대한 논의는 나중에 따로 스레드를 만드시지요. 저는 이 토론 말고 더 할만큼 시간은 없습니다. 이제 그만 하겠습니다.

Orion Project : http://orionids.org

체스맨의 이미지

B 인스턴스로 캐스트한다해도 원래 B 인스턴스가 할당된 것이었다면 문제가 없다는 것 쯤은 아시지 않습니까?

class B : public A { public: int x; };
 
A a, * pa;
B b, * pb;
 
pa = &a
pb = (B*)pa;
pb->x = 1234; // 오류
 
pa = &b
pb = (B*)pa;
pb->x = 1234; // 문제 없음

주장하시는 논지의 초점을 모르겠다는 말씀입니다.
C++ 의 몰이해로 나타날 수 있는 문제점을 말씀하시는 거면, 우선 주제와 관련이 없고, 그런 전제를 제대로 하지 않은 책임이 있습니다.

Orion Project : http://orionids.org

김일영의 이미지

마침 체스맨님께서 올리신바와 같이

class B : public A { public: int x; };
pa = &b
pb = (B*)pa;
pb->x = 1234; // 문제 없음

이거 됩니다.

그러니까 이런 생각을 하는 사람이 있는 겁니다.
"어차피 같은 인스턴스니까 A의 생성자에서 this를 받아놓고 그걸로 B 인스턴스를 참조해도 되겠구나?"

아 물론 이거 틀렸습니다! 제가 강조하는게 바로 그거고요!
그런데 this를 보존하겠다는 생각을 하시는 분 중에는 적지않은 분들이 저런 생각을 하십니다.
그래서 그런 실수를 하지 말라고 게시물을 올렸습니다. 그런데 무슨 책임?

미안하지만 그런 책임 운운하시려면 본인 홈페이지에서 하시는게 맞을 것 같네요.
전 사양합니다.

체스맨의 이미지

소모적 논쟁의 원인이 무엇이었는지 묻고 싶군요. :-)
일방적인 문제라고 할 수는 없지만, 문제가 일어난데에는 서로의 책임이 있기 마련이죠. 저도 참여한 이상 일정 부분의 책임이 있다는 것은 피하지 않습니다.

그런데 this를 보존하겠다는 생각을 하시는 분 중에는 적지않은 분들이 저런 생각을 하십니다.
그래서 그런 실수를 하지 말라고 게시물을 올렸습니다. 그런데 무슨 책임?

그런 실수를 하지 말라는 의미를 명확히 전달하지 못한 것을 말씀드린 것입니다. 김일영님의 답변이 원문에 대한 직접적 답변으로 원문 자체가 잘못된 것임을 주장하는 것으로 오해가 생긴 것으로 보여집니다. 처음부터 되짚어보셨으면 합니다.

"어차피 같은 인스턴스니까 A의 생성자에서 this를 받아놓고 그걸로 B 인스턴스를 참조해도 되겠구나?"

이런 판단도 '상황에 따라' 할 수 있고 구현에 적용할 수도 있습니다. 김일영님께서도 위와 같이 구현하는 것이 '반드시' 문제를 유발한다고 주장하는 것은 아니잖습니까?

어쨌든 무엇을 주장하시는 지는 알겠습니다. 저는 이 스레드에서 더 할말은 굳이 없군요. 이만 하겠습니다.

Orion Project : http://orionids.org

익명 사용자의 이미지

질문 올리신 곱단오빠님, 이것좀 확인시켜 주시길 바랍니다.

http://kldp.org/node/85645#comment-407825

Quote:
당연히 B와 A 간에 상속 관계가 있겠지... 대입가능하니까 저렇게 하려고 했을 것 아니시겠어?

김일영님께서 이렇게 말씀하십니다.

정말로 B와 A간에 상속관계가 있음을 가정하시고 질문을 올리셨습니까? 예 아니오로만 짧게 답글 달아주시면, 위에 체스맨 님이나 musiphil 님이 수고롭게 길게 써주지 않아도 쉽게 결말이 날 것 같습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.