코드짤때 여러분은 어떻게?
첫번째방식
vector<string>::iterator begin = m_vecString.begin(); vector<string>::iterator end = m_vecString.end(); BYTE byLength; while(...) { byLength = begin->length(); ...... }
두번째방식
while(...) { BYTE byLength = begin->length(); ...... }
왠만해서는 첫번째 방식으로 하는데 예를들어 while 문안에서
byLength 처럼 임시로 사용될 변수들이 많은경우 while문
위에 선언하면 코드가독성이 많이 떨어지더군요..
그래서 두번째 방식처럼 코드 안에 선언하고 싶은데 저런경우
루프 한번 돌때마다 계속 변수를 선언하지 않습니까? 그러면
제가 알기론 스택메모리를 계속 할당/해제(정확히는 스택포인트
의 증가/감소겠지만..)하는게 이게 그렇게 큰 오버헤드가 발생
하느냐가 궁금합니다...
생성자/소멸자에 많은 연산이 첨가된 클래스를 2번재방식처럼
하면 많은 부하가 발생할수도 있겠지만 일반 기본 데이타형(int,char*) 등
은 괜찮지 않을까 하는게 제 생각 입니다.
2번째로 작명인데
아래와 같은것을 typedef 을 할때
__gnu_cxx::hash_map<string, int>
보통 어떻이름으로 타입 디파인을 하시는지 궁금합니다.
키값을 기준으로 하는지 데이타값을 기준으로 하시는지
아니면 용도에 맞는 이름으로 하시는지요..
전화번호로 한다 치면
typedef __gnu_cxx::hash_map<string,int> PhoneNumberMap;
이렇게 하고 썼다고 해보죠. 근데 우편번호도 저 타입으로
쓸려고 합니다. 그러면
typedef PhoneNumberMap ZipCodeMap
이렇게 해서 쓰시는지요? 저는 보통 이렇게 하는데 일반적인
것인지 궁금합니다.
근데 용도에 맞게 typedef 을 해서 이름을 정할려고 하면
영 가독성있는 타입이름이 안나오네요...ㅜ.ㅜ 저만 그런지..
그렇다고 키값을 기준으로 하자니 좀 그렇고.. 지금 좀 많이
고민중입니다.
몇개 더 코드짤때 고민중인게 있는데 이 두가지 부분에 관해 kldp
여러분들의 의견을 듣고싶습니다.
Re: 코드짤때 여러분은 어떻게?
퍼포먼스와 가독성 간의 어느정도 trade가 있을지 모르겠지만 전자의 형태를 사용합니다. 공통적으로 사용되는 iterator 형태는 타이핑이 귀찮아서 typedef ... v_it 로 해두고 v_it begin = .. 형태로 쓸 것 같습니다.
"어째서 폰넘버와 집코드를 동일하게 했지?"
라는 생각이 들어서라도 이런 코드를 기피할 것 같습니다.
최선책은 둘을 다른 구조로 하는 것이고 차선책은 두 자료가 앞으로도 같을 거라면 공통된 특징을 잡아서 typedef를 하고 그걸 ZipCodeMap과 PhoneNumberMap에서 모두 다시 typedef하는 것 같습니다.
- 죠커's blog / HanIRC:#CN
저는 두번째 방식을 사용합니다. 어떤 변수가 의미있는 곳에서만 알려질 수
저는 두번째 방식을 사용합니다. 어떤 변수가 의미있는 곳에서만 알려질 수 있도록
scope를 잡는 것이 저의 원칙이거든요. 내장형의 경우 루프 안에서 매번 할당/해제가
반복될 수도 있는데, 이것은 컴파일러의 최적화와 관련이 있고 웬만한 컴파일러는
이런 최적화는 다 할 수 있을 거라고 생각합니다.
클래스 형이라면 당연히 생성자와 소멸자가 반복 호출되겠죠. 그러나 이것도 그리
큰 문제는 아니라고 봅니다. 루프 바깥에서 변수를 선언했다고 하더라도 루프 안에서
새로운 값을 대입하는 일은 하게 되겠죠. 그리고 보통 대입은 소멸과 새로운 값으로
초기화하는 내용으로 구현되는데, 그렇다면 실질적으로 생성자/소멸자가 호출되는
것이나 다름없습니다.
저는 성능보다는 코드의 논리적인 의미를 더 중시하는 편이라서 두번째 스타일을
선호하긴 하는데, 만약 성능상의 문제로 코드를 변경해야 하는 상황이라면 블럭
밖에서 선언하는 것도 고려해볼 수는 있겠습니다. 프로파일링을 거치긴 하겠지만요.
두번째 문제에 대해서는 CN님과 비슷한 생각입니다. 두 타입이 개념적으로 별로
관련이 없다면 따로따로 typedef 하겠습니다. 실제로는 같은 타입이라고 하더라도요.
작명 기술은 저도 딸리는 관계로 별로 드릴 말씀이 없네요. ^^;
지역 변수는 함수에 진입하는 순간 메모리(스택) 초기화가 이뤄지며, 생성
지역 변수는 함수에 진입하는 순간 메모리(스택) 초기화가 이뤄지며, 생성자는 호출 시점에 실행이 됩니다.
위와 같은 코드가 있을 때 각 지역 변수의 메모리(스택) 할당은 func() 함수가 진입하는 순간에 이뤄지며, 변수 a, b, c의 생성자는 호출 시점에 실행된다고 보면 됩니다.
다만, b, c의 경우에는 매 루프 실행마다 생성자, 소멸자가 실행됩니다. std::string과 std::vector는 내부적으로 동적 메모리 할당을 이용하므로 위와 같은 방식은 퍼포먼스에 문제가 생기겠죠.
어느 책에선가 봤던 내용인데 기억이 안나네요. 게다가 C++98 표준안에서도 관련 내용을 찾지 못하겠네요 ;;
저 같은 경우 작명은typedef __gnu_cxx::hash_map
저 같은 경우 작명은
typedef __gnu_cxx::hash_map<string,int> PhoneNumberMap;
이러게 하지 않고
typedef __gnu_cxx::hash_map<string,int> HStringInt;
이렇게 하고 실제 변수에
HStringInt PhoneNumber;
이렇게 합니다.
typename(HStringInt) 은 그 변수를(PhoneNumber) 어떻게 사용해야하는지 구분해주는 용도로 간주합니다.
typedef __gnu_cxx::hash_map<string,int> PhoneNumberMap;
만약 이렇게 선었했다면
PhoneNumberMap numMap;
이런식으로 하는건 같은 걸 두번 쓰는거나 다름없다고 생각하거든요.
그리고 스택은
kcando 님 말씀 처럼 스택포인터의 변화는 함수콜때만 변화하며
loop 같은데서는 변하지 않습니다. 그래서 loop 안에 int 와 같은 기본 타입이나 생성자가 없는 struct 같은건 포퍼먼스에 영향이 없습니다.
그리고 스택에서 작업하는건 대부분 1차 캐쉬에 적재되어서 작동하기 때문에
매우 빠릅니다. 포퍼먼스에 크리티컬한 섹션이 아니라면 가독성을 생각하시는것도 좋다고 봅니다.
궁금한점..
즉 펑션안에 어떤 블럭( while 문 블럭이나 if 문블럭 ) 안에
선언된 변수들은 이미 function 으로 진입 할때 스택에 적재
된다는 말씀이신지요?
즉 블럭안으로 들어갈때 할당됬다가 나오면 해제되는거라는
것이 아니라는 말씀이신데 이 경우라면 어떻게 클래스의 생성자
와 소멸자가 호출될수 있는것인지 궁금합니다. 할당 해제가
일어나므로 생성자와 소멸자가 호출되는것인데 말이죠.
궁금합니다 ^^
블럭 안으로 들어갔다가 나오면 생성과 소멸이 되는건 맞습니다.그래서
블럭 안으로 들어갔다가 나오면 생성과 소멸이 되는건 맞습니다.
그래서 생성자와 소멸자가 호출되는 것 역시 맞습니다.
다만 스택포인터의 사용법이 rasungboy님께서 생각하는 것과는 다르게 컴파일러는 처리할겁니다.
저도 예전에 이런 생각을 할때 스택포인터 처리를 이런식으로 하지 않을까 생각을 했습니다.
이런식으로요.
하지만 사실 이렇게 하지 않습니다.
함수 호출에 한번 셋팅된후
이렇게 처리 하면 sp 는 변수 생성시 변하지 않겠죠?
가독성만을 위한 것이라면...
단순히 scope 영역 내에서의 가독성을 위한 것이라면..
typedef TYPE 등으로 dummy definition을 만들어서 사용하시는게 좋지 않을까요..?
정말 performance에 영향이 없는 것이 확실하다면 필요없겠지만.. ^^;;
windmill on the windy hill....
댓글 달기