피터 고츠슐링 저/옥찬호 역 | 길벗
http://www.yes24.com/24/goods/57615943
C++을 안쓴지 오래되서 그런지 C++11, C++14 문법들이 너무 생소하다. 옛날 생각하고 Effective Modern C++을 읽기 시작했는데 너무 어려워서 기본 문법책을 고르는 중 이책을 보게 됨.
설명이 친절하진 않지만 C++11, C++14 내용을 한글로 설명하고 있어 빠르게 읽고 다시 Effective Modern C++을 읽어야 할 것 같음.
책을 보다가 기억해야 할 것들을 정리함.
더 자세한 내용은 책에 있으니 책을 읽어 보는것이 가장 좋겠음.
1장 C++ 기초
- C++14는 2진수를 0b, 0B 접두사로 표현함.
int b1 = 0b11111010;
가독성을 위해 ' 도 사용함.
long d = 61'234'567'890;
int x = 1010'0011'0000;
- 데이터가 손실되지 않는 uniform initialization, braced initalization을 사용함.
long l = {1231234567890};
int pi = 3.14; // 데이터 손실, 컴파일 가능
int pi = {3.14}; // 에러
* 값의 종류
Lvalue, Rvalue
Lvalue = 역사적으로, 대입 표현식의 왼쪽에 나타날 수 있기 때문에 붙여진 이름으로 함수나 개체를 말함.
Rvalue = 역사적으로, 대입 표현식의 오른쪽에 나타날 수 있기 때문에 붙여진 이름으로 만료된 값, 임시 개첸 그 하위 개체, 개ㅔ와 관련이 없는 값을 말함.
좀 말이 어려운데 아래 MSDN예시를 참조하면 더 이해하기 쉬움
https://msdn.microsoft.com/ko-kr/library/f90831hc.aspx
모든 C++ 식은 lvalue 또는 rvalue입니다.
lvalue는 단일 식을 넘어 지속되는 개체를 참조합니다. lvalue를 이름이 있는 개체로 생각할 수 있습니다. 수정할 수 없는(const) 변수를 비롯한 모든 변수가 lvalue입니다.
rvalue는 rvalue를 사용하는 식 외에서는 유지되지 않는 임시 값입니다.
// lvalues_and_rvalues1.cpp // compile with: /EHsc #include <iostream> using namespace std; int main() { int x = 3 + 4; cout << x << endl; }
아래 링크도 참고.
http://jeremyko.blogspot.kr/2012/08/lvalue-rvalue.html
- 곱셈과 나눗셈은 덧셈과 뺄셈보다 먼저 계산하고, 연산은 왼쪽에서 오른쪽 순서로 결합한다. ... 여러분이 정말로 중요하게 기억해야 할 것은 인수들의 계산 순서는 정의되지 않았다는 점이다. 예를 들어
int i = 3, j = 7, k;
k = f(++i) + g(++i) +j;
이 예제는 첫번째 덧셈이 두번째 덧셈보다 먼저 수행됨을 보장한다.
그러나 f(++i)와 g(++i)중 어느 표현식이 먼저 계산될 것인지는 컴파일러 구현에 따라 달라진다.
- 범위 기반 for 문
int odd_nums[] = {1,3,5,7,9,11};
for( int i : odd_nums)
std::cout << i << " ";
- 암수 오버로드는 signature가 서로 달라야 한다.
: 함수 이름
: 항(Arity)이라고 하는 인자의 개수
: (해당 순서대로) 인자의 타입
- 배열의 바이트 크기를 단일 항목의 바이트 크기로 나누면 배열의 크기를 알 수 있다.
: sizeof x / sizeof x[0]
- 포인터 초기화
: int* num1 = nullptr;
: int* num2{};
: int* bad1 = 0;
: int* bad2 = NULL:
- unique_ptr, shared_ptr, weak_ptr
https://msdn.microsoft.com/ko-kr/library/hh279674.aspx
unique_ptr
기본 포인터로 한 명의 소유자만 허용합니다.shared_ptr
이 필요하다는 점을 확실히 알 경우 POCO의 기본 선택으로 사용합니다. 새 소유자로 이동할 수 있지만 복사하거나 공유할 수 없습니다. 사용하지 않는auto_ptr
을 대체합니다.boost::scoped_ptr
과 비교합니다.unique_ptr
은 작고 효율적이며, 크기는 1 포인터이고 STL 컬렉션에서 빠른 삽입 및 검색을 위해 rvalue 참조를 지원합니다. 헤더 파일:<memory>
. 자세한 내용은 방법: unique_ptr 인스턴스 만들기 및 사용 및 unique_ptr 클래스를 참조하십시오.shared_ptr
참조 횟수가 계산되는 스마트 포인터입니다. 원시 포인터 하나를 여러 소유자에게 할당하려고 할 경우 사용합니다(예: 컨테이너에서 포인터 복사본을 반환할 때 원본을 유지하고 싶을 경우). 원시 포인터는 모든shared_ptr
소유자가 범위를 벗어나거나 소유권을 포기할 때까지 삭제되지 않습니다. 크기는 2개의 포인터입니다. 하나는 개체용이고, 다른 하나는 참조 횟수가 포함된 공유 제어 블록용입니다. 헤더 파일:<memory>
. 자세한 내용은 방법: shared_ptr 인스턴스 만들기 및 사용 및 shared_ptr 클래스를 참조하십시오.weak_ptr
shared_ptr
과 함께 사용할 수 있는 특별한 경우의 스마트 포인터입니다.weak_ptr
은 하나 이상의shared_ptr
인스턴스가 소유하는 개체에 대한 액세스를 제공하지만, 참조 수 계산에 참가하지 않습니다. 개체를 관찰하는 동시에 해당 개체를 활성 상태로 유지하지 않으려는 경우 사용합니다.shared_ptr
인스턴스 사이의 순환 참조를 차단하기 위해 필요한 경우도 있습니다. 헤더 파일:<memory>
. 자세한 내용은 방법: weak_ptr 인스턴스 만들기 및 사용 및 weak_ptr 클래스를 참조하십시오.
2장 클래스
위임 생성자
: https://msdn.microsoft.com/ko-kr/library/dn387583.aspx
class class_c { public: int max; int min; int middle; class_c(int my_max) { max = my_max > 0 ? my_max : 10; } class_c(int my_max, int my_min) : class_c(my_max) { min = my_min > 0 && my_min < max ? my_min : 1; } class_c(int my_max, int my_min, int my_middle) : class_c (my_max, my_min){ middle = my_middle < max && my_middle > min ? my_middle : 5; } }; int main() { class_c c1{ 1, 3, 2 }; }
위 예제를 단계별로 수행했다면,
class_c(int, int, int)
생성자가 class_c(int)
을 다시 호출하는 class_c(int, int)
생성자를 호출하는 것을 주목합니다. 각 생성자는 다른 생성자에서 수행되지 않는 작업만을 수행합니다.
호출하는 첫번째 생성자는 해당 지점에서 해당 멤버 모두가 초기화되도록 개체를 초기화합니다. 다음과 같이 다른 생성자에 위임하는 생성자의 멤버를 초기화할 수 없습니다.
class class_a { public: class_a() {} // member initialization here, no delegate class_a(string str) : m_string{ str } {} //can’t do member initialization here // error C3511: a call to a delegating constructor shall be the only member-initializer class_a(string str, double dbl) : class_a(str) , m_double{ dbl } {} // only member assignment class_a(string str, double dbl) : class_a(str) { m_double = dbl; } double m_double{ 1.0 }; string m_string; };
멤버의 기본 값
class에서 멤버 변수의 기본값을 설정할 수 있음.
class complex
{
public:
complex(double r, double i) : r{r}, i{i} { }
complex(double r) : r{r} { }
complex() { }
private:
double r = 0.0, i = 0.0
}
유니폼 초기화, 중괄호 초기화
: https://msdn.microsoft.com/ko-kr/library/dn387583.aspx
#include <string> using namespace std; class class_a { public: class_a() {} class_a(string str) : m_string{ str } {} class_a(string str, double dbl) : m_string{ str }, m_double{ dbl } {} double m_double; string m_string; }; int main() { class_a c1{}; class_a c1_1; class_a c2{ "ww" }; class_a c2_1("xx"); // order of parameters is the same as the constructor class_a c3{ "yy", 4.4 }; class_a c3_1("zz", 5.5); }
클래스에 기본이 아닌 생성자를 가질 경우, 중괄호 이니셜라이저에 클래스 멤버가 나타나는 순서는 멤버는 선언된 순서가 아니라 (
class_a
이전 예제에서와 마찬가지로 ) 생성자에서 해당 매개 변수가 나타나는 순서입니다. 그렇지 않고 해당 형식이 선언 된 생성자를 가지지 않을 경우, 중괄호 이니셜라이저에서 멤버가 나타나는 순서는 선언되어 있는 순서와 동일합니다; 이 경우, 대부분의 공용 멤버를 초기화할 수 있지만 모든 멤버를 건너뛸 수는 없습니다. 다음 예제에서는 선언 된 생성자가 없을 때 중괄호 초기화에서 사용되는 순서를 보여줍니다.class class_d { public: float m_float; string m_string; wchar_t m_char; }; int main() { class_d d1{}; class_d d1{ 4.5 }; class_d d2{ 4.5, "string" }; class_d d3{ 4.5, "string", 'c' }; class_d d4{ "string", 'c' }; // compiler error class_d d5("string", 'c', 2.0 }; // compiler error }
이동 문법
이동 생성자, 이동 할당 생성자
: https://msdn.microsoft.com/ko-kr/library/dd293665.aspx
// Move constructor. MemoryBlock(MemoryBlock&& other) : _data(nullptr) , _length(0) { std::cout << "In MemoryBlock(MemoryBlock&&). length = " << other._length << ". Moving resource." << std::endl; // Copy the data pointer and its length from the // source object. _data = other._data; _length = other._length; // Release the data pointer from the source object so that // the destructor does not free the memory multiple times. other._data = nullptr; other._length = 0; } // Move assignment operator. MemoryBlock& operator=(MemoryBlock&& other) { std::cout << "In operator=(MemoryBlock&&). length = " << other._length << "." << std::endl; if (this != &other) { // Free the existing resource. delete[] _data; // Copy the data pointer and its length from the // source object. _data = other._data; _length = other._length; // Release the data pointer from the source object so that // the destructor does not free the memory multiple times. other._data = nullptr; other._length = 0; } return *this; }
댓글 없음:
댓글 쓰기