분류 전체보기
-
항목29. 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라Effective Modern C++ 2022. 9. 24. 21:59
복사를 실행하는 C++98코드 기반을 C++11을 준수하는 컴파일러와 표준 라이브러리로 컴파일하면 소프트웨어가 저절로 더 빠르게 실행된다. 하지만 다음의 경우들은 지원하지 않는다. 사용하는 라이브러리가 이동을 지원하지 않는 경우. 이동 연산을 명시적으로 선언하지 않았을 때 이동 연산이 자동으로 지원되지 않는 경우. 이는 형식에 복사 연산이나 이동 연산, 소멸자가 하나라도 있으면 그러한 자동 작성은 일어나지 않는다. (항목 17) 또한 이동 연산을 삭제(비활성)한 경우도 포함. 다음 경우는 이동 의미론이 도움이 되지 않는 경우이다. 이동할 객체가 이동 연산들을 제공하지 않는 경우. 이 경우 이동 요청은 복사 요청이 된다. 이동할 객체의 이동 연산이 해당 복사 연산보다 빠르지 않은 경우. 이동이 일어나려면 ..
-
항목28. 참조 축약을 숙지하라Effective Modern C++ 2022. 9. 7. 18:57
template void func(T&& param); // 보편 참조 func에 왼값 인수가 전달되면 T는 왼값 참조로 연역, 오른값 인수가 전달되면 T는 비참조 형식으로 연역. (왼값 => T 는 형식&로 연역, 오른값 => T는 [형식]으로 연역) 왼값이 들어오면 void func(Widget& && param); 같은 형태가 된다. 여기서 참조 축약이 발생 Widget& &&은 =>Widget&가 된다. 참조 축약 : 참조에 대한 참조가 허용된 문맥에서, 두 참조 중 하나라도 왼값 참조이면 두 참조는 하나의 왼값 참조로 축약된다. 그렇지 않고 둘 다 오른값 참조이면 결과는 오른 값 참조이다. 오른값이 들어오면 void func(Widget&& param); (참조 축약 X) std::forward..
-
항목27. 보편 참조에 대한 중복적재 대신 사용할 수 있는 기법들을 알아 두라Effective Modern C++ 2022. 9. 6. 20:22
1. 중복적재를 포기하라 중복적재 대신 다른 이름의 함수 2개를 만들어라. logAndAdd -> logAndAddName & logAndAddNameIdx 2. const T& 매개변수를 사용한다. 이동대신 복사가 되는 등 효율성이 떨어지지만 보편참조와 중복적재의 상호작용에 의한 문제점은 피할 수 있다. 3. 값 전달 방식의 매개변수를 사용한다. class Person{ public: explicit Person(std::string n) // T&& 생성자를 대체한다. : name(std::move(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {} ... private: std::string name; }; int류 형식을 받으면 int를 받는..
-
항목26. 보편 참조에 대한 중복적재를 피하라Effective Modern C++ 2022. 9. 6. 20:16
std::multiset names; void logAndAdd(const std::string& name){ ... names.emplace(name); // 전역 자료구조에 추가한다. } 이때 오른값이나 문자열 리터럴을 매개변수로 넘겨주면 비효율적인 작동을 한다. 오른값은 이동을 할 수 있지만 복사를 수행하고, 문자열 리터럴은 std::multiset에 직접 생성할 수 있지만 임시 객체 생성과 복사를 수행한다. 이런 낭비를 줄이기위해 보편 참조를 사용해보자 template void logAndAdd(T&& name){ ... names.emplace(std::forward(name)); } std::string petName("Darla"); logAndAdd(petName); // 복사 logAnd..
-
항목25. 오른값 참조에는 std::move를, 보편 참조에는 std::forward를 사용하라Effective Modern C++ 2022. 8. 27. 14:47
class Widget{ Widget(Widget&& rhs) // rhs는 오른값 참조 : name(std::move(rhs.name)),p(std::move(rhs.p)) {...} ... } class Widget2{ template void setName(T&& newName) // newName은 보편 참조 { name = std::forward(newName); } ... } 오른값 참조 -> 오른값으로의 무조건 캐스팅을 적용해야 한다.(std::move를 통해서) 보편 참조 -> 오른값으로의조건부 캐스팅을 적용해야 한다.(std::forward를 통해서) 반환값 최적화 : 복사 버전에서, 만일 지역 변수 w를 함수의 반환값 을 위해 마련한 메모리 안에 생성한다면 w의 복사를 피할 수 있다. ..
-
항목24. 보편 참조와 오른값 참조를 구별하라Effective Modern C++ 2022. 8. 27. 14:47
책에는 보편 참조(universal reference)라 나오지만 일반적으로 전달 참조(forwarding reference)라고 한다. void f(Widget&& param); // 형식 연역 없음 (오른값 참조) Widget&& var1 = Widget(); // 형식 연역 없음 (오른값 참조) template void f(T&& param); // param은 보편 참조 auto&& var = var1 // var는 보편 참조 이 두 보편 참조 문맥의 공통점은 형식 연역이 일어난다는 점이다. 보편 참초가 오른값 참조인지 왼값 참조인지를 나타내는지는 보편 참조의 초기치가 결정한다. 보편 참조가 함수의 매개변수인 경우, 초기치는 그 함수를 호출하는 지점에서 제공한다. f(w); // f에 왼값이 전달..
-
항목23. std::move와 std::forward를 숙지하라Effective Modern C++ 2022. 8. 20. 23:37
std::move 와 std::forward 는 그냥 캐스팅을 수행하는 함수이다. std::move는 주어진 인수를 무조건 오른값으로 캐스팅하고, std::forward는 특정 조건이 만족될 때에만 그런 캐스팅을 수행한다. 즉 std::move 자체는 이동이 아니라 캐스팅을 시켜 이동에 적합하다는 것을 말해주는 것이다. 하지만 std::move() 로 오른값 캐스팅을 해도 이동이 아닌 복사가 되는 경우도 있다. 바로 const 객체를 오른값 캐스팅해도 const 객체여서 복사 연산이 된다. 즉 const 객체는 이동 요청을 해도 복사 연산으로 변환된다. std::forward()는 조건부 캐스팅이다. forward의 인수가 오른값으로 초기화 되었으면 오른값으로 캐스팅하고, 왼값으로 초기화 되었으면 그냥왼..
-
항목22. Pimpl 관용구를 사용할 때에는 특수 멤버 함수들을 구현 파일에서 정의하라Effective Modern C++ 2022. 8. 16. 17:10
Pimpl 관용구는 너무 긴 빌드 시간을 줄이는 방법이다. 기본적인 방식은 클래스의 자료 멤버들을 구현 클래스를 가리키는 포인터로 대체하고, 자료 멤버들을 구현 클래스로 옮기고, 포인터를 통해서 그 자료 멤버들에 간접적으로 접근하는 기법이다. class Widget { // 헤더 "Widget.h" 안에서 public: Widget(); ~Widget(); // 선언만 해둔다 Widget(Widget&& rhs); // 이동 연산 Widget& operator=(Widget&& rhs); // 선언만 해둔다 Widget(const Widget& rhs); // 복사 연산 Widget& operator=(const Widget& rhs); // 선언만 해둔다 ... private: struct Impl; ..