Effective의 잘못된 예시 코드에 대해서

dltkddyd의 이미지

operator* 함수가 레퍼런스로 반환할 필요 없다는 사실은 알지만 Effective C++이라는 서적에서 학습목적으로 잘못된 예시를 들어놨길래 똑같이 만들어봤습니다(Effective C++ 157쪽의 내용). 이 함수의 원형을 다음과 같이 선언했습니다.

const Parent& operator*(const Parent& right)

그리고 전체 코드는 다음과 같습니다.


#include <iostream>
using namespace std;
class Parent {
public:
     int m,n;
     Parent():m(0),n(0) {}
     Parent(int _m, int _n):m(_m),n(_n) {}
     bool operator==(const Parent& right) const {
      if(m==right.m && n==right.n) {return true;}
      else {return false;}
 }
 bool operator==(const Parent& right) {
      return (  right==(*this)  );
 }
 
 const Parent& operator*(const Parent& right) {//여기 이 함수입니다.
      static Parent temp(m*right.m, n*right.n);
      return temp;
 }
};
 
int main() {
     Parent obj1(5,6);
     Parent obj2(5,7);
     Parent obj3(6,6);
     Parent obj4(5,10);
 
     cout<<(obj1*obj2).m<<"  "<<(obj1*obj2).n<<endl;
     cout<<(obj3*obj4).m<<"  "<<(obj3*obj4).n<<endl;
      if(  (obj1*obj2)==(obj3*obj4) ) {//그리고 이 블록에서 궁금한 점이 있습니다.
          cout<<"The same."<<endl;
      }
      else {
          cout<<"The different."<<endl;
      }
     return 0;
}

해당 블록에서 항상 참을 반환합니다. 곱하기 연산값도 늘 같고요. 어떻게 obj1*obj2의 값과 obj3*obj4의 값이 한결같이 같나요?

첫 번째 obj1*obj2 연산에서 함수가 반환되어도 여전히 그 반환값이 데이터 영역에 존재하기 때문인가요?

이 operator*를 다음과 같이 고치면 *연산의 값은 다르게 나오긴 하는데 ==비교연산에서는 계속 true만 반환됩니다.

 const Parent& operator*(const Parent& right) {
     static Parent temp;
     temp.m=m*right.m;
     temp.n= n*right.n;
     return temp;
 }

혹시 operator==(obj1*obj2, obj3*obj4)

에서 반환되는 정적객체가 같은 것이기 때문일까요. 그러니까 obj1*obj2가 실행되고, obj3*obj4가 실행된다고 했을 때 반환되는 정적객체는 공통의 것이고, 그 값은 obj3*obj4의 값이 되버리면, obj1*obj2의 연산의 결과인 정적객체도 공통의 것이므로 같은 값이 되버린다. 그런 것인지요? 정말 잘 모르겠어요. 책의 내용이 잘 이해가 안되요.

kukyakya의 이미지

KLDP의 유저분들은 tunecolor님의 과외 선생님이 아닙니다. 제발, 정말 제발 기초부터 다지시길 바랍니다.

kaeri17의 이미지

static 이 뭘 뜻하는지 생각해 보세요.

dltkddyd의 이미지

프로그램 종료까지 살아남아 있는 변수니까. 그 생명주기는 전역과 같다고 할 수 있을 것 같고. 함수 내부의 정적 변수는 계속 그 함수에서도 동일한 변수니. 뭐 당연한 결과겠네요.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

책에 그게 왜 잘못된 예시인지는 안나와있던가요? 질문 글에 정적 객체라서 문제된다는 걸 본인도 짐작하고 있었던 것 같은데, 그걸 본인 손으로 직접 확인해보기보다는 먼저 게시판에 달려와서 다른 사람에게 대신 확인해달라고 하는 게 본인은 지금 떳떳하고 아무렇지도 않은 행동인가요?

dltkddyd의 이미지

그러니 답변 달지 마세요. 바보 같잖아요. 답변 달기 싫으면 안 달면 그만이지. 그런 글 올리네 마네 할 권리가 댁에게 없죠. 몰라서 물으면 그것도 모르냐, 짐작가는 것을 물어보면 그리 짐작가는 것을 왜 물어보냐고 하는 우스운 상황은 뭡니까. 그럼 너나 글 올리지 마세요. 싫으면 답변글 안 달면 되는 것을 왜 계속 답변을 다시나. 장난하냐?

익명님께 하는 얘기입니다. 다른 분들은 해당사항 없습니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

아니, 질문하기 전에 먼저 직접 해보시라고요 ㅋ 정적변수가 문제인 걸 짐작했으면, 위에서 operator==() 내부에서 양쪽 포인터 찍어봤어요?

문제해결을 위한 집념은 강하신 듯한데 방향이 이상하군요. 사람들한테 매달리지 말고 머신을 직접 파고 들라고요. 실력이 왜 안느는지 짐작이 ㅋ

dltkddyd의 이미지

디버거로 출력하는 방법좀 말해봐. 모르지? 그런 구식 방법 말고. 그런 방법은 니가 말한 디버거 방식이 아니잖어.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

ㅋㅋㅋ

자존심도 매우 강하시네요.

제 방식을 알려드리면, 간단한 건 printf로 해결하고, 데몬이면 로그로 남기죠. 양쪽 다 쓸 수 없는 경우에 - 덩치가 매우 크고 복잡해서 표준출력을 어디로 잡아먹는지 로그시스템이 어떻게 돌아가는지 파악하기 너무 귀찮은 경우 - gdb 씁니다.

매번 p로 찍는게 너무 너무 귀찮아질때쯤 되면 주섬주섬 매뉴얼 찾아서 watch 해놓습니다.

영 불편하면 ddd 같은 프론트엔드 쓰셔도 좋지만 전 그게 더 손에 안붙어서 걍 gdb 씁니다.

dltkddyd의 이미지

안되셨네. 벌써 이러시면 안되는데. 이제 퇴직할 데가 되신 듯 보이네요.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

첨언하면 printf로 찍는게 구식이고, 디버거로 돌리는게 대단하고 뭐 그런 거 아니예요. 문제 해결을 위해 그 상황에서 제일 적절하고 편한 방법을 쓰시면 됩니다. 뭔가 이상한 환상을 가지신 듯 ㅋ 다만 님은 동작 방식을 궁금해 하고 내가 알고 있는게 맞는지 확인하고 싶어하니까, 그러면 디버거로 하나 하나 흐름을 쫓아가면서 체크하시는게 님이 원하는 걸 얻는 지름길이다 이거죠.

뒤죽박죽인 용어와 개념들로 질문해봤자, 줄 수 있는 답도 그에 따라 왔다리 갔다리 부정확할 수 밖에 없어요. 게다가 이 사람이 대체 무슨 말 하는지 한참 파악해서 애써 대답해줘봤자 돌아오는 반응이 뭐였죠? ㅋ 님아, 질문 하기 전에 자기가 먼저 했어야 할 숙제부터 제대로 하세요. "전문가 집단"은 님 편한대로 이용해먹는 자판기가 아니예요. 배려 좋아하시네 ㅋ

익명 사용자의 이미지

그게 궁금하면 디버거로 한줄씩 한줄씩 트레이스하면서 변수와 포인터 값들을 확인하세요. 사람들은 님의 디버거가 아니예요.

dltkddyd의 이미지

GDB에서 멤버함수로 breakpoint를 걸어보세요. 되나 안 되나.
안 걸려서 그럽니다. 내가 잘못된 것인지. 분명 이렇게 했습니다.

break 멤버함수 이름

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

올바른 질문 방법:

GDB에서 멤버함수에 breakpoint 찍는 법을 모르겠습니다. GDB 매뉴얼에서 찾아봤는데 어느 내용이 그 부분인지 모르겠습니다. 알려주세요~

익명 사용자의 이미지

구글에서 gdb c++ member breakpoint 로 검색해보았습니다. 위에서 네번째가 GDB 매뉴얼의 해당 내용이고, 위에서 두번째는 스택오버플로우에 달린 비슷한 질문입니다. 스택오버플로우의 저 질문과 님의 질문이 어떻게 다른가를 잘 비교해보세요.

dltkddyd의 이미지

무슨 내용인지 해석해보세요.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

진지하게 말씀드리는데, 영어의 벽은 넘으셔야 합니다. 어차피 이쪽 영어는 그 용어들이 정해져있어서, 계속 읽고 찾아보고 하다보면 어느 정도 됩니다. 답 없습니다. 반복하세요.

dltkddyd의 이미지

해석 어렵지 않죠. 맨날 보느 것이 영문 레퍼런스인데요. 모국어보다 익숙한 것이 영어다?

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

자 그럼 이제 스스로 하실 수 있겠네요 ㅋ 잘 받아드셨나요?

익명 사용자의 이미지

옆에 곰돌이 인형 있죠? 걔한테 말해요

http://jhrogue.blogspot.kr/2007/05/bear.html

익명 사용자의 이미지

kldp 역대급 트롤에 등극해되 될 듯하네요.

dltkddyd의 이미지

갈채를 보냅니다. 우와....

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

제가 보기에 tunecolor님은 내부동작과 시스템에 대한 목마름을 C++ 랭귀지의 구현 방식을 파고 드는 것으로 해소하려 하시는 것 같습니다. C++ 언어의 추상적 개념들에 대한 건 비록 엄밀한 것은 아닐지라도, 어느 정도 잡혀 있는 것 같습니다. 문제는 거기에 갇혀서 정말로 시스템에 닿지를 못하고 있는거죠. 이런 건 C를 배우더라도 사실 마찬가지입니다.

라이브러리에 헤더 어떻게 만드냐고 질문하셨었죠? 다른 유명한 프로젝트들(매뉴얼이 잘되어있죠) 검색해서, 컴파일&인스톨하는 법부터 차근 차근 따라하세요. autotools 같은 건 지금은 배우기 어려우니 그냥 하라는대로 하고, 대충 보통은 이런 식으로 하다는 개념만 잡으세요.

읽고 계신 effective c++은 얼른 휘리릭 읽으시고, 본인만의 프로젝트를 시작하세요. 당장 make 파일을 어떻게 구성해야 하는지부터 벽에 부딪힐 겁니다. 그럼 make 매뉴얼을 읽으세요. 완벽하지 않아도 좋으니 처음 셋업이 되면, 코드를 작성하되, C++의 이상한 어두운 구석들에 대한 관심은 제발 멀리하시고, 지금까지 배운 best practice만 써서 한다는 각오로 하세요. 컴파일러(와 링커)의 각종 옵션들은, 내가 사용하는 도구의 사용법들은 틈날 때마다 읽어보시고요.

네트웍이든, DB든, UI든, 무언가 실제적인 것들을 만들려면 바닥부터 만들 생각 마시고 해당 라이브러리를 가져다 쓰는 법을 배우세요.

옆에 반드시 끼고 살아야 할 것은 C++ 기본서, STL 레퍼런스일 것이고 컴파일러, 빌드 툴, 갖다 쓰는 라이브러리의 매뉴얼, 각종 시스템콜 맨페이지 등은 필요한 순간 순간마다 끊임없이 찾아봐야 합니다. 매뉴얼 읽는 법, 레퍼런스 참조하는 법, 헬프 읽는 법은 처음에는 쉽지 않겠지만 계속 반복해서 하다보면 익숙해집니다. 이 벽을 넘지 못하면 안됩니다. 구글링은 그야말로 생활화 해야되고요. 그리고 그런 실제적인 문제들을 가지고 질문하시면, 훨씬 나은 반응을 얻으실 겁니다. 지금처럼 추상적이고 모호한 질문들 대신에요.

그런 식으로 무언가 만들어가다보면, 내가 제대로 가고 있다는 확신을 얻으실 수 있을 겁니다. 결국 뭔가를 만들어내는 법을 배우려는 것 아닙니까.

jick의 이미지

이분 글 묘하게 중독성이 있다고 느끼는 건 저뿐인가요?
...아 이런 데 빠지면 안되는데......

익명 사용자의 이미지

책은 열심히 읽었고 머릿 속으로 시뮬레이션은 해봤는데 정말 그런지 아닌지는 모르겠다 -> 그런데 직접 툴 쓰는 법도 잘 모르겠고 직접 확인해볼 방법은 없다 어쩌지? -> "책은 읽었는데 정말 모르겠어요 ㅠㅠ" -> 낚인 넘이 답을 해준다 -> 뭐, 이미 알고 있었어

왜 툴 쓰는 법을 모를까? 안해봤으니까. 왜 안해봤을까? 그런 복잡하고 골치아픈 거 대신 해줄 "놈"들은 널렸거든. 숙제와 시험에 그런 건 안나오니까..

그러면서도 잘나가긴 또 잘나가서 열라 피곤하죠.

물론 어떤 분인지는 전혀 모르니 글 쓴 분 얘기는 아닙니다. 그냥 비슷해서요.

가만보면 이상한게, 정직하게 제 실력 쌓은 케이스도 없지 않은데, 외려 다른 이들보다 더 겸손하고 성실해서 계속 같이 일하고 싶죠.