[EffectiveC++ 요약] 1장. C++에 왔으면 C++의 법을 따릅시다.
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
항목1. C++은 여러 언어의 연합체
= C
= 객체 지향 개념의 C++
= 템플릿
= STL
= 위 4가지로 구성
항목2. #define을 쓰려거든 const, enum inline을 떠올리자
Ex] #define TEST_Ratio 1.653 사용 시, 기호 테이블에 들어가지 않음 (Symbol Table)
= 소스 -> 전처리기 -> 컴파일러 순으로 진행 시,
= TEST -> 1.653으로 바꿔버려 어디에 오류가 있는지 찾기 힘듬
(사족) 컴파일 에러를 말하는지, Logic 에러를 말하는지 모르겠네
= TEST_Ratio가 사용된 만큼 메모리가 사용
(TEST_Ratio -> 1.653으로 바꾸기에, TEST_Ratio 등장 횟수 만큼 리소스 사용
= 매크로 대신 상수를 쓰는 방법으로 대체
(const double TestRatio = 1.653)
= 상수 포인터 정의하는 경우 주의 사항
= char* 형식 문자열 상수 정의시 , ptr과 value까지 const로 선언하는 것이 보통
Ex]
const char* const AuthorName = "Test Author";
-> const char* (Ptr에 대한 Const)
-> const AuthorName (Value에 대한 Const)
char* 보단 std::string을 쓰는것이 좋다
const std::string AuthorName("Test Author");
항목2-1. 클래스 상수 정의
Ex]
class Player{
private:
static const int NumTurns = 5; //상수 선언
...
};
(사족) numTurns는 객체가 사용되기 이전에 PreProcess 단계에서 만들어지기에 static이 필요할것으로 보인다. (미리 메모리에 올라가 있어야하니...)
= NumTurns는 선언 된 것, 정의가 아니다. (값이 5로 선언)
= 컴파일 시, NumTurns에대해 정의를 달라고 하는데, 이 경우 구현 파일 쪽에 정의를 선언한다.
(컴파일러 버전에 따라 틀림, 정의 시점에 해당 값을 선언하는 경우가 낫다)
Ex]
Player.h
class Test Player{
private:
static const double NumTurns; // 정적 클래스 상수 선언
};
Player.cpp
const double Player::NumTurns = 1.35 // 정적 클래스 상수의 정의
항목2-2. enum hack 기법 (나열자 둔갑술)
= 만약 컴파일 시점 배열을 선언할 일을 만든다면? enum으로 작업을 하자
class Player{
private:
enum { NumTurns = 5 };
int scores[NumTurns];
};
= 해당 기법은 const 보다 #define에 가깝다.
Ex]
1. const int a = 5, <- 주소 획득 가능
2. 위 enum NumTurns <- 주소 획득 불가
3. #define <- 주소 획득 불가
= 정수 상수의 주소를 얻는 것이나 참조자를 쓰는것이 싫다면, enum은 좋은 선택지
(#define처럼 쓸데없는 리소스 할당을 하지 않는다)
= Enum Hack기법은 템플릿 메타프로그래밍의 핵심 기법
항목2-3. #define의 오용 사례
= 매크로 함수, 호출 오버헤드를 일으키지 않는 매크로 구현
Ex]
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
= 인자마다 괄호를 씌워 주어야한다. (표현식을 넘길 때 문제)
= 괄호가 있어도 문제가 발생
Ex]
int a = 5, b = 0
1. CALL_WITH_MAX(++a, b) // A가 두번 증가
2. CALL_WITH_MAX(++a, b+10) // A가 한번 증가
(사족) 왜 1번은 두번 증가일까. 초기 인자로 넘어가기 전 한번 증가, 비교 후, (a)리턴 시 한번 더 증가,
1. (a,b)
2. f((a) > (b) ?
3. (a) : (b)
2에서 ++a 연산 진행
3에서 ++a 연산 진행
= 값으로 넘어오지않고 연산식으로 넘어오기에 계속 증가가되버리는 케이스
(사족) 2번의 경우 b가 더 크기에, 비교식에서만 증가
= 좀더 나은 방안은?
template<typename T>
inline void callWithMax(const T& a, const T& b)
{
f ( a > b ? a : b);
}
= T, 즉 자료형이 무엇인지 모르기에, Paramterter 선언 시, 상수 객체 참조자를 쓴다.
(사족) Object가 넘어 올 수 있기 때문에, 상수 객체 참조자를 쓰는듯 하다. (복사생성으로 인함)
= 소스 코드 내 괄호 필수 아님
= 인자 여러번 평가 위험 없음
= 함수의 유효범위 및 접근 규칙을 그대로 따라간다.
= const, enum inline을 활용하면 #define 경우가 많이 줄어듬.
= 단순 상수 쓸 때, #define보다 const 객체 or enum 을 우선 생각
= 함수처럼 쓰이는 매크로 생성 시, #define 보다 인라인 함수
항목3. 낌새만 보이면 const를 들이대자
= '의미적인 제약(const 키워드 붙엇을 경우, 외부 변경 불가)'을 소스코드 수준에서 붙이는 점과, 컴파일러가 이를 지켜준다는 점을 활용
= 클래스 바깥에서 전역 혹은 네임스페이스 유효범위의 상수를 선언(정의)하는데 사용
= static 선언 객체에도 const 가능
(클래스 내부에서 정적 멤버, 비정적 데이터 멤버 모두 상수 가능)
= 포인터 자체를 상수, 포인터가 가르키는 데이터를 상수로 지정 가능
Ex]
char greeting[] = "Hello";
1) char* ptr = greeting; // 비 상수 데이터, 비상수 포인터
2) const char* p = greeting; // 상수 데이터, 비상수 포인터
(사족) ptr 변경은 가능, 데이터는 불가? 테스트 필요....
3) char* const p = greeting; // 비상수 데이터, 상수 포인터
(사족) ptr변경 불가, 데이터는 가능?
4) const char* const p = greeting // 상수 포인터, 상수 데이터
= const가 * 왼쪽이면, 가르키는 대상이 상수
오른쪽이면, 포인터 자체가 상수
= 아래는 동일한 내용
void f1(const Widget *pw)
void f2(Widget const *pw)
= 두 매개변수는 동일하다, (가르키는 대상이 상수, *왼쪽에 const선언되었기에)
= STL 반복자는 기본적인 T* 포인터와 흡사
= Iterator, Ptr에 대한 상수화
const std::vector<int>::iterator iter = vec.begin()
(위 내용은 T* const iter와 같다고 생각하면된다.)
*iter = 10; // value를 수정한다.
++iter; // ptr을 한단계 이동 (불가, ptr이 상수)
= value에 대한 const를 지정위해서는 const_iterator를 써야한다.
Iterator, Value에 대한 상수화
std::vector<int>::const_iterator cIter = vec.begin();
(*cIter) = 10; // value에 대한 const지정으로 에러
++cIter // 가능, ptr는 상수가아니다.
= *Return Object에 대한 Const
Ex]
const Rational operator*(const Relational& lhs, const Rational& rhs)
Relational a, b, c;
...
(a * b ) = c 일때,
1. a * b 연산자 오버로딩 발생
2. 두 연산결과에 대한 대입 연산 발생
(사족) 이런 상황이...?
const로 오버로딩 설정이 되어있으면, 이런 상황이 방지된다.
(사족) 2. 대입 연산 과정에서, const로 선언되었기에 값에 대한 수정이 일어나면 안되기 때문일거같다.
= 상수 멤버 함수
해당 멤버 함수가 상수 Object에서만 호출되는 함수
선언 이유.
1. 클래스 인터페이스 이해하기 좋게 하기 위함
= 내부에서 값이 변경되는 함수는 무엇이고 안되는 함수는 무엇인지 명시적 정의
2. 키워드를 통해 상수 객체를 사용할 수 있게 하자
= 핵심적
= C++ 의 성능을 높이는 기법
상수 객체에 대한 참조자로 진행
위 기법을 쓸려면 상수 멤버함수가 있어야함
Ex]
class TextBlock{
public:
...
(1) const char& operator[](std::size_t position) const // 상수객체에 대한 operator[]
{ return text[position]; }
(2) char& operator[](std::size_t position)
{ return text[position]; }
private:
std::string text;
};
TextBlock tb("Hello");
std::cout << tb[0]; // TextBlock::operator[]의 비 상수 멤버 호출
(2) Function 실행
const TextBlock ctb("World")
std::cout << ctb[0]; // TextBlock::Operator[]의 상수 멤버 호출
(1) Function 실행
(사족) Object가 Const이면, 강제하는 것이기에 충분한 상황판단 후 써야할듯 하다.
실제 프로그램에서 상수 객체가 생기는 경우
1. 상수 객체에 대한 포인터
2. 상수 객체에 대한 참조자로 객체 전달될 때
(아래형식으로 상수객체 전달사용하는듯)
void print(const TextBlock& ctb) // ctb는 상수 객체 사용
{
std::cout << ctb[0]; // TextBlock::operator[] 의 상수멤버 호출
....
}
위 형식으로 상수 객체와 비상수 객체의 쓰임을 달리하면 좋다
Case
Ex]
std::cout << tb[0] // 문제 없음, 비상수 버전의 TextBlock 객체를 읽습니다.
tb[0] = 'x' // 문제 없음, 비상수 버전의 TextBlock 객체를 쓴다.
std::cout << ctb[0] // 문제 없음 상수 버전의 TextBlock 객체를 읽음
ctb[0] = 'x' //컴파일 에러, 상수 버전의 TextBlock 객체 쓰기 안됨
ctb[0] = 'x'의 경우, operator[]의 반환 타입(return type) 때문에 생긴 것
const char& 타입에 대한 연산을 시도했기 때문에 생긴 것
= 상수 멤버로 되어있는 operator[]의 반환 타입이 const char& 이기 때문!
항목3-1. 상수성의 개념
비트 수준 상수성(bitwise constness)
= 어떤 멤버 함수가 그 객체의 어떤 데이터 멤버도 건드리지 않아야 그 멤버 함수가 const임을 인정하는 개념
(사족) 비트 수준에서 바뀌지 않아야 한다는 의미 일까?
= 비트수준 상수성 검사를 통과하는 멤버함수들이 적지 않다
-> 가르키는 대상을 수정하는 멤버 함수들 중 상당수가 이 경우 속함
Ex]
class CTextBlock{
public:
...
char& operator[](std::size_t position) const // 부적절한 operator[] 선언, 비트수준 상수성이 있어 허용됨
{ return pText[position]; }
private:
char* pText
};
위 operator는 상수 멤버함수로 선언되어있음.
그런데, 해당 객체 내부 데이터 참조자로 반환
아래에 대해 컴파일러 단계에서는 잡아낼 수 없다.
const CTextBlock cctb("Hello") // 상수 객체 선언
char* pc = &cctb[0] // 값 확인
*pc = 'J'; // 상수 객체인데, 값이 수정되는 문제
논리적 상수성(logical constness)
위를 보완하는 대체 개념
=> 상수 멤버라고 해서 객체의 한 비트도 수정할 수 없는 것이 아닌, 몇 비트는 바꿀수 있게...
=> 사용자 측에서 알아채지만 못하게하자
=> 그렇다면 상수 멤버 자격이 있는 것
class CTextBlock{
public:
...
std::size_t length() const;
private:
char *pText;
mutable std::size_t textlength; // 직전 계산한 텍스트 길이
mutable bool lengthIsValid; // 이게 유효함?
};
std::size_t CTextBlock::length() const
{
if ( !lengthIsValid )
{
textLength = std::strlen(pText); // 상수 멤버 함수 안에서는 textLength, lengthIsValid에 대입 불가
lengthIsValid = true;
}
return textLength;
}
textLength = std::strlen(pText)
lengthIsValid
두 멤버는 mutable이 선언되지 않으면 const객체 선언 불가
(const하지 않으니...)
(사족)이처럼 부분 정도는.. 바꿀 수 있게 하는거 같다..
항목3-2. 상수 멤버 및 비상수 멤버 함수에서 코드 중복을 피하는 방법
= mutable은 나쁘지 않은 방법이지만, 코드 중복이 생김...
const char& operator[] ...
{
// 경계 검사
// 접근 데이터 로깅
// 자료 무결성 검증
return text[position];
}
char& operator[] ...
{
// 경계 검사
// 접근 데이터 로깅
// 자료 무결성 검증
return text[position];
}
각 메소드 마다 이런 코드들이 필요해지는 상황...
별도의 멤버로 빼두면?
그래도 중복은 여전함. (함수 호출이 두번...)
솔직히
한번만 구현하고 두번 사용하는것이 제일 깔끔하다...
캐스팅 개념은?
=> 좋지않은 아이디어 추후 얘기.
결론
= 캐스팅이 필요하긴 하지만 안정성도 유지하면서 코드 중복을 피하는 방법은....
비 상수 operator[]가 상수 버전을 호출하도록 구현
class TextBlock
{
public:
const char& operator&[] ( std::size_t position ) const
{
위와 동일
return text[position];
}
char& operator&[] ( std::size_t position )
{
return const_char<char&> // operator[] 반환 타입에 캐스팅 적용, const 붙임
(static_cast<const TextBlock&> // *this의 타입에 const 붙임
(*this)[position] // op[]의 상수버전 호출
);
}
};
위 작업은
= 비 상수 operator가 상수 operator가 불려야 하는 것
= 내부적으로 operator[]로 호출하면 재귀적으로 돌기에 안됨.
= *this를 타입캐스팅 해버린다.
첫번째 캐스팅, static_cast<const TextBlock&>는 *this에 const를 붙이는 캐스팅
두번째 캐스팅, const_char<char&>는 operator[]의 반환값에서 const를 떼어내는 캐스팅
(사족) 굳이 이렇게까지 Rule을 지켜야하는지는 의문...
상수 멤버 함수는 객체의 논리적인 상태를 바꾸지 않겠다고 컴파일러와 논의된 함수
비상수 멤버 함수는 약속을 굳이 하지 않음
상수멤버에서 비 상수 멤버 호출 시, 이 룰이 지켜지지 않게되어 위험할 수 있음
항목3-3. 객체를 사용하기 전에 반드시 그 객체를 초기화하자
= 초기화 되지 않은 값을 읽도록 내버려 두면, 정의되지 않은 동작이 그대로 흘러나옴
( 쓰레기값이 채워지는 케이스가 있기 때문... 일거같다 )
= 대입(assignment)와 초기화(initialization)을 구분지어서 진행하자
(사족) 대입의 경우에는 값의 Setter와 동일한 일을 할거 같다.
(사족) 초기화의 경우에는 값의 초기화를 담당한다.
= 생성자에서 일을 진행하자...
생성자에서 값, 객체를 초기화 할때, 멤버 initializer를 사용하면 더 깔끔
TestEntry::TestEntry(.... const std::list<PNumber>& phones)
: ...,
thePhonse(phones)
{
}
기존 본문에서 할당 시,
1. Parameters phones에 복사생성
2. Paramteres Phones -> thePhonse에 복사 생성
두번의 복사생성이 일어나는데,
위 방식은 한번의 복사 생성이 한번만 일어남
멤버 initializer의 경우에는 파라미터를 바로 할당하는 형식으로 진행된다.
기본 생성자도 아래의 방식으로 진행하는것이 좋다
TestEntry::TestEntry()
: theName(),
theAddress(),
numTimesConsulted(0)
thePhonse(phones)
{}
멤버 초기화 리스트의 의무사항
= 상수 or 참조자 로 되어있는 멤버의 경우 초기화 리스트로 해야함
Ex]
class TestEntry{
public:
const char* test;
TestEntry(const char* psTest)
: test(psTest)
{}
};
(사족) 테스트는 안해봣지만, 위 형식일듯하다...
항목 3-4. non-static, static 객체 초기화 순서
= static 객체는 생성된 시점부터 끝날 때 까지 살아있는 객체가 됨.
(스택, 힙, 객체는 애초에 정적 객체가 될 수 없다)
static 객체
1. 전역 객체
2. 네임스페이스 유혀범위 정의 객체
3. 클래스 안 static 선언 객체
4. 함수 안에서 static 선언 객체
5. 파일 유효범위에서 static 정의 객체
함수 안 정적 객체는 지역 정적 객체(함수의 지역성을 가지기에...)
나머지는 비지역 정적 객체 라고한다.
다섯 종류의 객체, 즉 정적 객체는 프로그램 끝날때 자동 소멸된다.
main()함수의 실행 끝날 때, 소멸자 호출
번역 단위(translation unit)는 objectfile 만드는 방탕이 되는 소스코드 (.cpp, .c의미하는듯..)
= 번역단위에서는 정의된 비지역 정적 객체들의 초기화 순서는 정해져있지않음.
즉 Compile 하는 순서대로 초기화가 될수도, 안될수도 있다는 것...
= 위를 강제할려면... 비지역 정적 객체를 하나씩 맡는 함수를 준비, 이 안에 객체를 넣는 것
비지역 정적 객체 -> 지역 정적 객체로 변환하는 것
class FilsSystem{ ... } ;
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
Directory::Directtory( params )
{
...
std::size_t disks = tfs().numDisks();
...
}
함수로 쓰면, 함수에서 초기화를 하기에, 순서에 보장을 가져올수 있다.
다중 스레드의 경우에는 문제가 될 수 있음.
(비상수 정적 객체는 시한폭탄... )
항목 3-4의 정리
1. 멤버가 아닌 기본 제공 타입 객체는 직접 초기화하자
2. 객체의 모든 부분에 대한 초기화에는 멤버 초기화 리스트 사용
3. 별개의 번역 단위에 정의된 비지역 정적 객체에 영향을 끼치는 불확실한 초기화 순서 염두
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
이 블로그의 인기 게시물
윤석열 계엄령 선포! 방산주 대폭발? 관련주 투자 전략 완벽 분석
## 1. 배경 2024년 12월 3일, 윤석열 대통령이 국가 비상사태를 이유로 계엄령을 선포하였습니다. 계엄령은 전시나 사변 등 국가의 안녕과 공공질서가 심각하게 위협받을 때 대통령이 군사적 권한을 통해 이를 방어하고 유지하기 위해 발효하는 특별한 조치입니다. 이러한 조치는 국내 정치·경제 전반에 큰 영향을 미치며, 특히 주식시장에서는 관련 기업들의 주가 변동이 예상됩니다. 24.12.03 오전 5시 계엄 해제로 아래 관련주 추천 - [윤석열 계엄령 해제! 이재명 관련주 급등? 투자자 필독 전략](https://warguss.blogspot.com/2024/12/yoon-martial-law-lift-lee-jaemyung-stocks.html) --- ## 2. 기업 및 관련주 ### 2-1 식품 관련주 - 계엄령이 선포되면 사회적 불안정성이 증가할 수 있으며, 이에 따라 생필품 및 음식 관련 주식이 단기적으로 강세를 보일 가능성이 있습니다. #### 1. CJ제일제당 (KOSPI: 097950) [시가총액: 약 10조 원] - **주요 산업**: 식품 및 생필품 제조 - **관련주 근거**: 국가적 위기 상황에서 식료품 수요가 증가하며, 즉석밥, 가공식품 등의 판매가 확대될 가능성이 있습니다. - **주가정보**: [네이버 차트](https://finance.naver.com/item/main.nhn?code=097950) #### 2. 오뚜기 (KOSPI: 007310) [시가총액: 약 3조 원] - **주요 산업**: 식품 제조 및 유통 - **관련주 근거**: 라면, 즉석식품 등 비축 가능한 식품 수요가 증가하며, 매출 상승이 기대됩니다. - **주가정보**: [네이버 차트](https://finance.naver.com/item/main.nhn?code=007310) #### 3. 대상 (KOSPI: 001680) [시가총액: 약 2조 원] - **주요 산업**: 식품 제조 및 발효제품 - **관련주 근거**: 계엄...
한국 핵무장 논의와 방위산업 관련주: 핵무기 개발 과정과 유망 종목 분석
한국의 독자적 핵무장 논의가 주요 이슈로 떠오르며 방위산업 관련 주식들이 주목받고 있습니다. 특히, 핵무기 및 방어 관련 기술력을 보유한 기업들이 관심을 끌고 있어 투자자들에게 큰 잠재적 수혜가 예상됩니다. 트럼프 전 미국 대통령의 재집권 가능성 등 외교적 변화는 이러한 방위산업 관련주를 더욱 부각시키고 있습니다. --- ### 핵무기 생산과정 요약 #### **핵연료 확보** : 고농축 우라늄-235 또는 플루토늄-239와 같은 핵분열 물질을 확보하는 과정입니다. - **우라늄 농축**: 우라늄-235의 비율을 약 90% 이상으로 높이는 과정입니다. - **플루토늄 생산**: 원자로에서 우라늄-238을 중성자로 포획하여 플루토늄을 생성하고 이를 화학적으로 분리합니다. #### **폭발 장치 개발** : 확보한 핵연료를 폭발할 수 있도록 설계된 장치입니다. - **충돌 방식 (Gun-type)**: 고농축 우라늄을 이용해 두 덩어리를 빠르게 결합시켜 핵분열을 유도합니다. - **내부 압축 방식 (Implosion-type)**: 고폭압력으로 플루토늄을 압축하여 임계 질량을 초과하도록 합니다. ####. **무기화 및 배치** - 폭발 장치를 무기 형태로 조립하여 배치 가능한 상태로 만드는 과정입니다. 미사일, 폭격기 등에 탑재될 수 있도록 설계합니다. --- ### 핵심적인 부분 가장 중요한 부분은 **핵연료 확보**와 **폭발 장치 개발**입니다. - **핵연료 확보**: 핵분열 물질 확보가 핵무기 개발의 필수 조건입니다. 우라늄 농축과 플루토늄 생산은 고도의 기술력을 요구하며, 보안과 국제적인 감시가 강화된 부분입니다. - **폭발 장치 개발**: 핵연료가 있어도 이를 효과적으로 폭발시키는 장치가 없다면 무기화가 불가능합니다. 압축 방식 등 폭발 장치 개발 기술이 핵무기의 폭발력과 신뢰성을 좌우하는 중요한 요소입니다. --- ### 핵연료 확보 관련 기업 - **한전원자력연료 (KEPCO NF)** :...
[로스트아크] 제작 효율 최적화 위한 영지 세팅
### 1. 대성공 확률 증가 vs. 제작 수수료 절감 - **대성공 확률 증가**: 대성공 확률이 2% 증가해도 실제 효과는 크지 않습니다. 예를 들어, 기본 대성공 확률 5%에 2% 증가를 적용해도 실질적인 효과는 0.1% 증가에 불과합니다. - **제작 수수료 절감**: 제작 수수료를 2% 절감할 경우, 제작할 때마다 발생하는 골드 비용을 직접적으로 줄일 수 있어 비용 절약 효과가 훨씬 큽니다. - 결과적으로, 제작 수수료 절감이 대성공 확률 증가보다 약 10배 더 많은 이득을 제공합니다. 따라서 대성공 확률보다는 수수료 절감에 집중하는 것이 권장됩니다. --- ### 2. 효율적인 영지 세팅을 위한 이득 극대화 세팅 - 영지 내 필수 세팅 아이템으로 "곡예사의 대기실," "찬란한 소원 나무," "여신의 가호"가 추천됩니다. - **곡예사의 대기실**: 마리샵에서 블루 크리스탈로 구매할 수 있으며, 기본적인 제작 효율을 높이는 데 필수 아이템입니다. - **찬란한 소원 나무**: 수수료 절감을 제공하여 제작 비용을 절감하는 효과가 있어 이득 극대화에 도움이 됩니다. - **여신의 가호**: 미술품 42개를 모아 획득할 수 있으며, 추가적인 제작 효율을 제공합니다. 여유가 있다면 필수로 장착하는 것이 좋습니다. - 여신의 가호 대신, **곡예사의 무기 진열대**를 구매해 사용할 수도 있으며, 경제적인 선택지로 활용할 수 있습니다. --- ### 3. 의상 세팅 (선택적 적용) - 특정 의상을 착용하면 제작 효율이 약간 증가하지만, 최적의 의상 옵션은 없기 때문에 필수는 아닙니다. 크리스탈 비용이 부담스러울 경우 생략 가능하며, 다른 세팅을 우선적으로 강화하는 것이 좋습니다. - **드레스룸 이용**: 크리스탈을 사용하여 드레스룸에서 특정 NPC와의 호감도로 얻을 수 있는 의상을 구매할 수 있습니다. - **추천 의상**: 페...
댓글
댓글 쓰기