[C++] Effective C++ : Chapter 1 C++에 왔으면 C++의 법을 따릅시다
목차
Chapter 1: C++에 왔으면 C++의 법을 따릅시다
항목 1: C++ 언어들의 연합체로 바라보는 안목은 필수
포인터는 메모리의 스택 영역에 있고 포인터가 가리키는 객체는 힙에 있다!
항목 2: #define을 쓰려거든 const, enum, inline을 떠올리자
Q. #define 매크로의 유효 범위는?
A. 컴파일이 끝날 때까지다.
항목 3: 낌새만 보이면 const를 들이대 보자!
Q. 아래의 코드에서 값을 변경하지 못하도록 const를 붙이고 싶습니다. 어디에다가 const를 붙이는게 좋을까요?
char* authorName = "Scott Meyers";
A. 값이 변경되지 않도록 앞쪽에 const를 붙이면 된다. 하지만 주소값도 변경되지 않게 const를 하나 더 붙이는게 좋다.
const char* authorName = "Scott Meyers"; // 값 변경x const char* const authorName = "Scott Meyers"; // 값 변경x + 주소값 변경x
Q. mutable 키워드는 어떤 역할을 할까요?
A. mutable 키워드는 비트 수준의 상수성를 풀어주기 위해서 사용하는 키워드입니다.
- C++이 만들어내는 기본적인 함수는, 생성자, 소멸자, 복사생성자, 복사 연산자 입니다. 이 4가지 모두 inline 함수로 만들어진다는데 알고 계셨나요? 저는 이 책을 읽고 알게 됐습니다.
- const_cast 를 사용해서 상수성을 풀어주기 보다, mutable을 사용해서 논리적으로 상수성을 풀어주는 방법도 있다는 사실을 기억하자!
Q. 아래 두 멤버 함수는 같은 오버로드일까요 다른 오버로드일까요?
class MyClass { public: void A(); //read - write void A() const; //read-only };
A. “오버로드된 함수에 대한 호출이 모호합니다”란 문구가 나오며 컴파일 되지 않습니다.
void A(int a); void A(const int a);
Q. 아래 상황에서 발생하는 문제는?
#include <iostream> using namespace std; class TextBlock { public: TextBlock(string te) : text(te){} public: char operator[] (std::size_t position) { return text[position]; } private: std::string text; }; int main() { const TextBlock tb("Hello"); tb[0] = 'x'; return 0; }
A. tb[0] = ‘x’ 컴파일 에러 발생합니다.
기본제공 타입을 반환하는 함수의 반환 값을 수정하는 일은 절대로 있을 수 없기 때문입니다.
반환 시 ‘값에 의한 반환’을 수행하는 C++의 성질 상 수정되는 값은 tb.text[0]의 사본이지 tb.text[0] 자체가 아닙니다.

“==로 생각하고 친 건데 실수로 =를 쳤네”와 비슷한 컴파일 에러를 보게 될 일이 없을겁니다.
레퍼런스를 쓰는데 안전하게 넘기기 위해 const랑 같이 사용합니다.
위와 같이 컴파일 에러가 나지 않도록 코드를 고치면 아래와 같습니다.
#include <iostream> using namespace std; class TextBlock { public: TextBlock(string te) : text(te){} public: char& operator[] (std::size_t position) { return text[position]; } private: std::string text; }; int main() { TextBlock tb("Hello"); tb[0] = 'x'; return 0; }
항목 4: 객체를 사용하기 전에 반드시 그 객체를 초기화하자
객체를 구성하는 데이터의 초기화 순서
- 기본 클래스는 파생 클래스보다 먼저 초기화한다.
- 클래스 데이터 맴버는 그들이 선언된 순서대로 초기화된다.
Q. 비지역 정적 객체들의 초기화 순서 문제를 어떻게 해결할까요?
별개의 번역 단위에서 정의된 비지역 정적 객체들의 초기화 순서는 '정해저 있지 않습니다.'
비지역 정적 객체들의 초기화 순서 문제를 해결하기 위해서 비지역 정적 객체를 지역 정적 객체로 바꾸는 방법이 있습니다. 함수 속에 넣어서 정적 객체로 선언하고 이들에 대한 참조자를 반환하게 합니다. 비지역 정적 객체를 직접 참조하는 상황을 없애고 함수 호출로 대신하여 문제를 해결할 수 있습다.
Q. 다음 중 옳은 것은?
1. 클래스는 선언과 동시에 멤버 변수가 초기화된다. 구조체도 선언과 동시에 멤버 변수가 초기화된다.
2. 클래스는 선언과 동시에 멤버 변수가 초기화된다. 구조체는 선언과 동시에 멤버 변수가 초기화 되지 않는다.
3. 클래스는 선언과 동시에 멤버 변수가 초기화되지 않는다. 구조체는 선언과 동시에 멤버 변수가 초기화된다.
4. 클래스는 선언과 동시에 멤버 변수가 초기화되지 않는다. 구조체도 선언과 동시에 멤버 변수가 초기화 되지 않는다.
4번. 클래스와 구조체는 선언과 동시에 자동으로 멤버 변수가 초기화되지 않습니다.
Q. 생성자에 멤버 초기화 리스트를 사용하는 것이 값을 대입하는것 보다 좋은 이유는 뭘까요?
멤버 초기화 리스트는 복사 생성자 한 번 호출하는 반면 값을 대입하면 기본 생성자 호출 후에 복사 대입 연산자를 연달아 호출합니다. 따라서 복사 생성자를 한 번 호출하는 방법이 더 효율적입니다.
Q. 아래의 코드를 읽고 각각 생성인지 대입인지 설명해보세요.
Pos pos1(10); // 복사 생성자 Pos pos2 = 20; // 생성자인가 복사 생성자인가? Pos pos3; // 기본 생성자 pos3 = 2; // 복사 대입 연산자로 대입
둘 다 대입이 아니라 생성하는 것입니다.
왜? 선언과 동시에 초기화를 해주었으므로.
대입이라는 것은 결국, 객체들이 다 만들어진 후에 값을 넣어주는 것입니다.

초기화 리스트 쓰면 복사 생성자.
Q. 디자인 패턴 중 하나인 싱글톤 패턴의 문제점은 멀티플레이에서 나옵니다. 어떤 문제가 발생할 수 있을까요?
A.
- 플레이어가 여러명인데 각각의 다른정보를 가져올 때 공통된 값을 가져오는 경우
- 경쟁상태에 빠져서 교착상태에 빠진다. → 싱글톤 패턴 때문일까? ⇒ 그렇습니다!
- static 키워드가 붙어서 사용합니다.
싱글톤 패턴은 하나의 인스턴스만을 생성하도록 하는 디자인 패턴입니다. 이는 많은 경우에 유용하게 사용될 수 있지만, 멀티스레드 환경에서 사용될 때 문제가 발생할 수 있습니다. 멀티스레드 환경에서의 싱글톤 패턴의 문제점은 다음과 같습니다:
1. Race Condition
- 멀티스레드 환경에서 여러 스레드가 동시에 싱글톤 인스턴스를 생성하려고 할 때, 경쟁 조건이 발생할 수 있습니다. 두 스레드가 동시에 인스턴스의 존재 여부를 확인하고 없다고 판단한 후에 인스턴스를 생성하는 경우가 생길 수 있습니다.
2. 지연 초기화의 안전성 문제
- 싱글톤 인스턴스가 필요한 시점에 생성되는 "지연 초기화" 방식을 사용하는 경우, 여러 스레드가 동시에 해당 인스턴스를 생성하려고 할 때 안전한지 보장하기 어려울 수 있습니다.
3. 메모리 가시성 문제
- 멀티코어 프로세서에서는 각 코어가 자체 캐시를 가질 수 있으며, 이로 인해 메모리의 변경 사항이 다른 코어에 즉시 반영되지 않을 수 있습니다. 이러한 메모리 가시성 문제로 인해 한 스레드에서 싱글톤 인스턴스를 수정한 내용이 다른 스레드에서 올바르게 보이지 않을 수 있습니다.
4. 해결 방안의 복잡성
- 위의 문제를 해결하기 위해서는 추가적인 동기화 메커니즘이나 스레드 세이프한 초기화 방법이 필요합니다. 이로 인해 코드가 복잡해지고 성능에 영향을 줄 수 있습니다.
이러한 문제를 해결하기 위해서는 싱글톤 패턴을 구현할 때 스레드 안전성을 고려하여야 합니다. 이를 위해서는 스레드 안전한 초기화 방법을 사용하거나, 미리 인스턴스를 생성하여 초기화하는 등의 방법을 사용할 수 있습니다.
'⭐ Programming > Effective C++' 카테고리의 다른 글
[C++] Effective C++ : Chapter 6 상속, 그리고 객체 지향 설계 (0) | 2024.05.07 |
---|---|
[C++] Effective C++ : Chapter 5 구현 (0) | 2024.04.28 |
[C++] Effective C++ : Chapter 4 설계 및 선언 (0) | 2024.04.17 |
[C++] Effective C++ : Chapter 3 자원관리 (0) | 2024.04.13 |
[C++] Effective C++ : Chapter 2 생성자, 소멸자 및 대입 연산자 (1) | 2024.04.10 |
댓글
이 글 공유하기
다른 글
-
[C++] Effective C++ : Chapter 5 구현
[C++] Effective C++ : Chapter 5 구현
2024.04.28Effective C++ : Chapter 5 구현 항목 26: 변수 정의를 늦출 수 있는 데까지 늦추는 근성을 발휘하자. Q. 아래 코드에서 encrypted 변수를 어떻게 초기화하고 있을까요? 아래의 보기 중 옳은 것을 고르시오.std::string encryptPassword(const std::string& password){ std::string encrypted(password); }1. string의 기본 생성자에 의해 만들어지고 password 값이 대입된다.2. string의 복사 생성자에 의해 초기화된다.더보기답: 2번 ( 185~186쪽 )불필요한 기본 생성자 호출이 일어나지 않고 변수의 의미가 명확한 상황에서 변수를 정의함과 동시에 복사 생성자에 의해 초기화가 이루어지고 있… -
[C++] Effective C++ : Chapter 4 설계 및 선언
[C++] Effective C++ : Chapter 4 설계 및 선언
2024.04.17Effective C++ : Chapter 4 설계 및 선언 항목 18: 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 Q. 인터페이스에 대해 설명해보세요.더보기소프트웨어식 인터페이스: 응용프로그램과 운영체제 간의 통신을 연결해주는 인터페이스언어적인 인터페이스:순수 가상함수로만 이루어진 클래스 Q. 인터페이스를 설계할 때, shared_ptr 을 사용하면 좋은 이유에 대해 설명해보세.더보기사용자 정의 삭제자를 통해 교차 DLL 문제 예방할 수 있습니다.반환 타입을 포인터가 아닌 shared_ptr로 만들어서, 메모리 누수 예방할 수 있습니다. Q. 교차 DLL 문제(cross-DLL problem)에 대해 설명해보세요. 왜 교차 DLL 문제가 발생할까요? 이에 대한 해결방안으로… -
[C++] Effective C++ : Chapter 3 자원관리
[C++] Effective C++ : Chapter 3 자원관리
2024.04.13프로그래밍에서 자원(Resource)이란, 사용 후에 시스템에 돌려주는 모든 것을 통칭한다. C++ 프로그래밍에서는 동적으로 할당한 메모리는 메모리 누수가 발생하지 않도록 적절히 해제해주어야 한다. 목차 Effective C++ : Chapter 3 자원관리 항목 13: 자원 관리에는 객체가 그만! Q. 아래 코드를 사용하면 어떤 상황이 벌어질까요?shared_ptr spi(new int[1024]); 컴파일도 잘 된다. 동적 배열에 대한 메모리가 문제없이 잘 해제된다.컴파일 에러가 발생한다. 메모리가 해제되지 않는다.컴파일 에러가 발생하지 않는다. 메모리가 해제되지 않는다.더보기shared_ptr 는 소멸자 내부에서 delete[] 연산자가 아니라 delete 연산자를 사용하므로 동적으로 할… -
[C++] Effective C++ : Chapter 2 생성자, 소멸자 및 대입 연산자
[C++] Effective C++ : Chapter 2 생성자, 소멸자 및 대입 연산자
2024.04.10목차 Chapter 2: 생성자, 소멸자 및 대입 연산자 항목 5: C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자 Q. C++이 만들어내는 기본적인 함수는 무엇이고, 어떠한 형태로 생성할까요? 프로그래머기 만들지 않으면 컴파일러가 기본으로 생성해주는 멤버 함수가 뭐가 있을까요?더보기A. 기본적인 함수는 복사 생성자, 복사 대입 연산자, 소멸자입니다. 생성자조차도 선언되어 있지 않으면 역시 컴파일러가 기본 생성자를 선언합니다. 이 4가지 함수는 inline 함수 형태로 생성됩니다.추가로 이동 생성자, 이동 대입 연산자도 생성됩니다public - inline 은 컴파일러가 선택한다.move&&… (가변길이 템플릿)코드복사형태https://modoocode.com/290" data…
댓글을 사용할 수 없습니다.