포스팅 계기
오랜만에 블로그 글을 다시 쓰게 되었는데, 글이 뜸했던 핑계는 출장도 잦고 결혼식 준비로 인해 결정해야 할 사항들이 많아서 포스팅이 없었다. 그래서 다시 블로그도 시작하고 코딩 공부도 해야 할 것 같은데... 시작을 어떤 것으로 하면 좋을까 고민을 하다가... 나만의(?) C++ 코딩 습관을 공유해 보면 어떨까? 하는 생각에 해당 주제를 선정하게 되었다. 물론 내가 가지고 있는 습관이 다른 개발자들도 많이 가지고 있을 것으로 예상한다. 그래서 조금 다르게 이러한 습관을 왜 가지게 되었는지도 같이 기재하려고 한다. 이번 포스팅 이후에는 알고리즘 문제 및 새로운 Rust언어를 공부하면서 글을 써보려고 한다. 앞으로 많(은) 관(심) 부(탁) :)
비교 연산자 상수 위치
개발을 하면서 보면 아래와 같이 코드를 작성하는 사람들이 대부분이다. 아래의 코드를 보면 당연히 문제가 없다. 하지만 현업에서 일을 하다 보면 아래와 같은 구문도 문제가 발생할 수 있다.
UINT uVariable = 4;
if( uVariable == 3 )
{
// 어떠한 동작 기재
}
문제 발생 코드를 보면 == 이 =로 되어 있다. 하지만 빌드에러는 발생하지 않는다. 변수에서다가 값을 대입하는 것이기 때문이다. 그러면 누군가는 말한다. 누가 그런 실수를 해요? 하지만.. 협업을 하다 보면 아래와 같은 코드들이 종종 보인다. 일이 바쁘기 때문에 단순한 동작에서 많은 실수가 생기기 때문이다. 근데 더 골치가 아픈 건... 아래와 같은 구문이 있는 경우 잘못된 값을 대입하면서 오동작을 할 경우 찾기가 어렵다는 것이다..
UINT uVariable = 4;
if( uVariable = 3 ) // 비교가 아니라 대입을 하는 문제가 발생
{
// 어떠한 동작 기재
}
그래서 나는 아래와 같이 순서를 바꾸어 내가 실수를 하게 되는 경우 빌드에러가 발생하도록 하여 실수를 줄이고 있다.
UINT uVariable = 4;
if( 3 == uVariable )
{
// 어떠한 동작 기재
}
Const & 파라미터
const & 파라미터는 많은 개발자들이 제대로 알고 있을지? 또한, 같이 협업하는 개발자 중 사용하는 개발자도 많이 보지 못했다. 단순하지만 함수가 자주 호출되는 경우 실수도 줄이고, 성능에 미미한 영향을 줄 수 있는 코드를 알아보자
void FunctionA( const UINT & rParam )
{
// 함수 동작
}
보통 매개변수에 const로 기재하는 이유는 전달받은 파라미터는 정보용으로만 사용하고 절대 수정하지 않으니깐 const로 선언하게 된다. ※ 자세한 const는 https://kiswiss77477.tistory.com/12 포스팅을 참고해 주기 바란다.
근데 추가로 &까지 사용하는 이유는 값 복사를 막기 위해서다. 보통 아래와 같은 함수를 선언하면 실행 시 다음과 같은 순서로 변수가 전달된다. uTemp 값을 전달하기 때문에 FunctionA에서 uParam은 4라는 값을 가지는 임시 변수가 복사되어서 사용된다. 하지만 & 하게 되면 주소 값이 전달되기 때문에 복사 연산이 줄어들게 된다.
void FunctionA( const UINT uParam )
{
// 동작 기재
}
main()
{
UINT uTemp = 4;
FunctionA(uTem);
return 0;
}
생성자 초기화 리스트
생성자 초기화 리스트는 위에 주제들에 비해 많은 개발자들이 애용하고 있는 방법이다. 일단 간단하게 방법을 설명하면 생성자 옆에 : 로 시작하여 변수(초기값) ,.... , 변수(초기값)로 사용한다.
Class Manager
{
private:
UINT m_uManagerNum ;
Manager() : m_uManagerNum(0)
{
//....
}
}
그러면 생성자 초기화 리스트를 사용하는 이유는 무엇일까? 생성자 내에서 멤버 변수에 값을 대입하는 것은 초기화가 아니라 할당이다. 또한, const 나 & 멤버 변수의 경우에는 초기화 리스트에서는 초기화가 가능하지만, 생성자 내에서 할당을 할 경우 에러가 발생한다. 이 처럼 초기화 리스트를 활용해서 초기화를 하게 되면, 불필요한 할당을 막을 수 있어 애용하는 편이다.
__forceinline
C++ 개발을 해본 사람들이라면 inline 함수는 알고 있을 거라 생각이 된다. 하지만 forceinline은 사용하지 않는 개발자가 많다. forceinline을 설명하기 이전에 inline라는 키워드 먼저 설명을 간단하게 하면, 함수 호출 시 오버헤드를 줄이기 위해 함수를 호출하는 대신 함수 코드를 복사해서 사용하기 위한 방법이다.
아래와 같은 함수를 작성하여 사용하는 경우 FunctionA의 구문이 main 함수에 복사가 된다고 생각하며 된다. inline이 없는 경우에는 호출 스택으로 FunctionA로 넘어가는 동작이 생략되는 것이다. 그러면 무조건 사용해야겠네?라고 생각할 수 있지만, 코드가 복사된다는 의미는 파일의 사이즈가 커진다는 의미다. 그래서 나는 보통 수학적 계산이나 단순한 게 Set Get이 자주 호출되는 동작에 사용한다.
하지만 inline의 경우 개발자가 inline 키워드를 사용한다고 해서 무조건적으로 inline 함수가 되는 것이 아니다.. 그러며 다들 (?)라는 게 머리에 그려질 것으로 예상된다. 그 이유는 컴파일러가 판단 후 inline 함수를 할지 말지 결정하기 때문이다. 이러한 것을 방지하고자 forceinline 키워드를 사용하면 개발자의 의도대로 사용된다.
inline FunctionA ( const UINT & rParam )
{
// 동작
}
main()
{
UINT uTemp = 0;
FunctionA(uTemp);
return 0;
}
함수 내 코드 100 줄 넘지 않기
개인적으로 함수가 100줄을 넘는다면 함수가 기능에 맞게 구현된 것인지? 고민을 해봐야 한다고 생각한다. 보통 구현을 하다 보면 기능을 분리할 수 있음에도 불구하고 한 함수에 엄청나게 긴 코드를 작성하는 개발자들이 있다. 그러면 가시성도 떨어지고, 분명 실수가 생긴다. 될 수 있으면 중복된 구문은 함수로 분리하고, 최대한 함수는 함수 기능에 맞게 그 이외의 동작은 빼는 것을 추구한다.
정리
나만의 방법이라고 하지만 많은 개발자들이 애용하고 있을 것으로 예상된다. 그럼에도 불구하고 포스팅을 한 이유는 내가 알고 있던 지식이 맞는지 검토 및 혹시나 모르는 개발자들에게 공유하기 위함이다. 다음 포스팅부터는 조금 더 유익한 포스팅으로 찾아오겠다. Bye Bye
'C++ 개발이야기' 카테고리의 다른 글
C++ 개발자의 반성 (2) | 2025.04.16 |
---|---|
실무에서 경험한 C++ 멀티스레딩과 스마트 포인터 문제 및 해결 방법 (0) | 2025.03.05 |
C++ 개발자로서 성장하는 법: 나의 경험과 팁 (0) | 2025.03.05 |
멀티 쓰레드(Multi Thread) (0) | 2024.01.17 |
Thread Lib(Windows) - C ++ (0) | 2024.01.05 |