You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -539,6 +540,12 @@ C++14 에서는 이와 같이 작성할 수 있다. C++ 11 환경이라면, `fac
539
540
540
541
필요한 경우에만 고급 기술을 사용하고, 주석으로 문서화하라.
541
542
543
+
문자열 전달은 [String](./SL.md#SS-string) 참고.
544
+
545
+
##### Exception
546
+
547
+
`shared_ptr` 타입을 사용한 공유 소유권을 표현하려면 F.16-21 지침을 따르기보다는 [R.34](./References.md/#Rr-sharedptrparam-owner), [R.35](./References.md/#Rr-sharedptrparam) 및 [R.36](./References.md/#Rr-sharedptrparam-const)을 참고하라.
548
+
542
549
### <a name="Rf-in"></a>F.16: "입력(in)" 매개변수는 복사 비용이 적게 드는 타입의 경우 값으로 전달하고, 그 외에는 상수 참조형으로 전달하라
543
550
544
551
##### Reason
@@ -578,39 +585,22 @@ C++14 에서는 이와 같이 작성할 수 있다. C++ 11 환경이라면, `fac
578
585
void sink(unique_ptr<widget>); // input only, and moves ownership of the widget
579
586
```
580
587
581
-
아래와 같은 "난해한 기술"은 지양하라:
582
-
583
-
* "효율적이라서" 인자를 `T&&`로 전달한다. `&&`로 전달함으로써 발생하는 성능 향상에 대한 루머는 잘못되었고 깨지기 쉽다(속단하지 말고 [F.18](#Rf-consume)와 [F.19](#Rf-forward)를 참고하라)
584
-
* 대입에서 `const T&`를 반환하거나 비슷한 연산을 수행한다 ([F.47](#Rf-assignment-op) 참고)
585
-
586
-
##### Example
587
-
588
-
`Matrix`가 이동 연산을 지원한다고 가정하자(아마도 원소들을 `std::vector`에 보관하고 있다):
589
-
590
-
```c++
591
-
Matrix operator+(const Matrix& a, const Matrix& b)
592
-
{
593
-
Matrix res;
594
-
// ... fill res with the sum ...
595
-
return res;
596
-
}
597
-
598
-
Matrix x = m1 + m2; // move constructor
599
-
600
-
y = m3 + m3; // move assignment
601
-
```
588
+
"효율적이라서" 인자를 `T&&`로 전달한다. `&&`로 전달함으로써 발생하는 성능 향상에 대한 루머는 잘못되었고 깨지기 쉽다(속단하지 말고 [F.18](#Rf-consume)와 [F.19](#Rf-forward)를 참고하라)
602
589
603
590
##### Notes
604
591
605
-
반환 값 최적화는 대입에 대해서는 동작하지 않지만, 이동 대입의 경우에는 적용된다.
606
592
참조는 언어 규칙에 의해 유효한 개체를 가리킨다고 가정하기 때문에, null 참조는 발생하지 않는다.
607
593
optional 값에 대해 알고 있다면, 포인터를 사용하거나, `std::optional` 혹은 "값이 없음"을 의미하는 특별한 값을 사용하라.
608
594
609
595
##### Enforcement
610
596
611
-
* (쉬움) (기본 사항) 인자의 크기가 `4 * sizeof(int)` 보다 크면 경고한다. `const` 참조를 전달하도록 제안한다
612
-
* (쉬움) (기본 사항) `const` 참조로 전달되는 인자의 크기가 `3 * sizeof(int)`보다 작다면 경고한다. 값 전달을 대신 사용하도록 제안한다
613
-
* (쉬움) (기본 사항) `const` 참조 매개변수가 `move`되면 경고한다
597
+
* (쉬움) (기본 사항) 인자의 크기가 `2 * sizeof(void*)` 보다 크면 경고한다. 대신 `const` 참조를 전달하도록 제안한다.
598
+
* (쉬움) (기본 사항) `const` 참조로 전달되는 인자의 크기가 `2 * sizeof(void*)` 이하면 경고한다. 대신 값을 전달하도록 제안한다.
599
+
* (쉬움) (기본 사항) `const` 참조 매개변수가 `move`되면 경고한다.
600
+
601
+
##### Exception
602
+
603
+
`shared_ptr` 타입을 사용하여 공유 소유권을 표현하려면 함수가 전달인자를 참조하는지 여부에 따라 [R.34](./References.md/#Rr-sharedptrparam-owner) 또는 [R.36](./References.md/#Rr-sharedptrparam-const)를 참고하라.
f2(and, forward<PairLike>(pairlike).second, in, another, call); // forward .second
728
+
}
709
729
```
710
730
711
731
##### Enforcement
712
732
713
-
* 모든 정적 경로에 대해 단 한번 `std::forward`하는 경우를 제외하고 `TP&&` 매개변수를 받는 함수를 지적한다 (`TP`는 템플릿 인자의 이름이다).
733
+
* 모든 정적 경로에 대해 단 한번 `std::forward`하는 경우를 제외하고 `TP&&` 매개변수를 받는 함수를 지적한다. (`TP`는 템플릿 인자의 이름이다) 또는 `std::forward`을 한 번 이상 수행하지만 정적 경로마다 정확히 한 번씩 다른 데이터 멤버로 자격을 부여한다.
734
+
735
+
> * Flag a function that takes a TP&& parameter (where TP is a template type parameter name) and does anything with it other than std::forwarding it exactly once on every static path, or std::forwarding it more than once but qualified with a different data member exactly once on every static path.
714
736
715
737
### <a name="Rf-out"></a>F.20: "출력(out)"에는 매개변수보다는 값을 반환하는 방법을 선호하라
716
738
@@ -736,28 +758,32 @@ optional 값에 대해 알고 있다면, 포인터를 사용하거나, `std::opt
736
758
737
759
(각각의 이동 비용이 크지 않은) 멤버를 많이 가진 `struct`는 전체적으로는 이동 비용이 클 수 있다.
738
760
739
-
`const` 값을 반환하는 것은 추천하지 않는다. 오래된 조언들은 무의미하다: 의미도 없고 이동 의미구조를 방해한다.
761
+
##### Exceptions
762
+
763
+
* 상속 계층 구조에 속한 타입처럼 값 타입이 아닌 경우, 개체를 `unique_ptr` 혹은 `shared_ptr`로 반환하라.
764
+
* 만약 값의 이동 비용이 크다면 (`array<BigTrivial>` 같은 경우), 자유 저장소에 할당하고 그 핸들을 (`unique_ptr`와 같은) 반환하는 것을 고려하라. 또는 `const`가 아닌 참조(출력 매개변수)를 전달해 개체를 채워넣도록 하라.
765
+
* 최대 크기(capacity)를 가진 개체(예를 들어 `std::string`, `std::vector`)를 여러 함수 호출 과정에서 재사용하고자 한다면, [입출력 매개변수로 참조를 전달하라](#Rf-out-multi).
740
766
741
-
```c++
742
-
const vector<int> fct(); // bad: that "const" is more trouble than it is worth
767
+
##### Example
743
768
744
-
vector<int> g(const vector<int>& vx)
769
+
`Matrix`가 이동 연산을 지원한다고 가정하자(아마도 원소들을 `std::vector`에 보관하고 있다):
770
+
771
+
```c++
772
+
Matrix operator+(const Matrix& a, const Matrix& b)
745
773
{
746
-
// ...
747
-
fct() = vx; // prevented by the "const"
748
-
// ...
749
-
return fct(); // expensive copy: move semantics suppressed by the "const"
774
+
Matrix res;
775
+
// ... fill res with the sum ...
776
+
return res;
750
777
}
751
-
```
752
778
753
-
반환 값에 `const`를 사용하는 것은 임시 변수에 대한 (굉장히 드문) 우발적 접근을 막기 위한 것이다.
754
-
전달 인자에 `const`가 사용되면 (매우 자주 발생하는) 이동 의미구조를 막는다.
779
+
Matrix x = m1 + m2; // move constructor
755
780
756
-
##### Exceptions
781
+
y = m3 + m3; // move assignment
782
+
```
783
+
784
+
##### Notes
757
785
758
-
* 상속 계층구조에 속한 타입처럼 값 타입이 아닌 경우, 개체를 `unique_ptr` 혹은 `shared_ptr`로 반환하라
759
-
* 많약 값의 이동 비용이 크다면 (`array<BigPOD>` 같은 경우), 자유 저장소에 할당하고 그 핸들을 (`unique_ptr`와 같은) 반환하는 것을 고려하라. 또는 `const`가 아닌 참조(출력 매개변수)를 전달해 개체를 채워넣도록 하라
760
-
* 최대 크기(capacity)를 가진 개체(예를 들어 `std::string`, `std::vector`)를 여러 함수 호출과정에서 재사용하고자 한다면, [입출력 매개변수로 참조를 전달하라](#Rf-out-multi).
786
+
반환 값 최적화는 대입에 대해서는 동작하지 않지만, 이동 대입의 경우에는 적용된다.
761
787
762
788
##### Example
763
789
@@ -777,15 +803,16 @@ optional 값에 대해 알고 있다면, 포인터를 사용하거나, `std::opt
777
803
##### Enforcement
778
804
779
805
* 큰 비용 없이 반환할 수 있으면서 값을 변경하기 전에 사용하는 비 `const` 참조 매개변수를 지적하라; 이들은 "출력" 반환 값이 적절하다.
780
-
*`const` 반환 값을 지적한다. `const`를 제거하도록 권한다
781
806
782
807
### <aname="Rf-out-multi"></a>F.21: "출력"값 여러 개를 반환할 때는 튜플이나 구조체를 선호하라
783
808
784
809
##### Reason
785
810
786
811
반환 값은 그 자체로 문서가 필요하지 않고 "출력 전용"으로 사용된다.
787
-
C++ 에서는 다수의 값을 반환할때는 `tuple`(`pair`를 포함해)를 쓴다는 것을 기억하라, 호출한 지점에서 `tie`를 사용해 받을 것이다.
788
-
반환 값에 의미구조가 있다면 별도의 struct 타입을 사용하라. 그렇지 않다면 일반적인 코드에서는 (이름 없는) `tuple`이 유용하다.
812
+
C++ 에서는 다수의 값을 반환할때는 튜플과 유사한 타입(`struct`, `array`, `tuple` 등)를 쓴다는 것을 기억하라,
813
+
호출한 지점에서 구조화된 바인딩(structured bindings)(C++17)을 추가로 편리하게 사용할 수 있다.
814
+
반환 값에 의미구조가 있다면 별도의 `struct` 타입을 사용하라.
815
+
그렇지 않다면 일반적인 코드에서는 (이름 없는) `tuple`이 유용하다.
789
816
790
817
##### Example
791
818
@@ -799,39 +826,33 @@ C++ 에서는 다수의 값을 반환할때는 `tuple`(`pair`를 포함해)를
799
826
}
800
827
801
828
// GOOD: self-documenting
802
-
tuple<int, string> f(const string& input)
829
+
struct f_result { int status; string data; };
830
+
831
+
f_result f(const string& input)
803
832
{
804
833
// ...
805
-
return make_tuple(status, something());
834
+
return {status, something()};
806
835
}
807
836
```
808
837
809
-
사실, C++98의 표준 라이브러리에서는 `pair`가 개체 2개를 묶은 `tuple`과 같기 때문에 이 기능을 편리하게 사용하고 있었다.
810
-
811
-
예를 들어, `set<string> my_set`이 주어졌다고 가정하면:
838
+
C++98의 표준 라이브러리에서는 일부 함수에서 `pair`를 반환하는 스타일을 사용했다. 예를 들어, `set<string> my_set`이 주어졌다고 가정하면:
812
839
813
840
```c++
814
841
// C++98
815
-
result = my_set.insert("Hello");
816
-
if (result.second) do_something_with(result.first); // workaround
817
-
```
818
-
819
-
C++11에서는 이렇게 작성할 수 있다, 결과값들을 이미 존재하는 지역변수에 대입한다:
820
-
821
-
```c++
822
-
Sometype iter; // default initialize if we haven't already
823
-
Someothertype success; // used these variables for some other purpose
824
-
825
-
tie(iter, success) = my_set.insert("Hello"); // normal return value
826
-
if (success) do_something_with(iter);
842
+
pair<set::iterator, bool> result = my_set.insert("Hello");
843
+
if (result.second)
844
+
do_something_with(result.first); // workaround
827
845
```
828
846
829
847
C++ 17에서는 다수의 변수들을 선언과 동시에 초기화 할 수 있는 "structured bindings"을 지원한다:
830
848
831
849
```c++
832
-
if (auto [ iter, success ] = my_set.insert("Hello"); success) do_something_with(iter);
850
+
if (auto [ iter, success ] = my_set.insert("Hello"); success)
851
+
do_something_with(iter);
833
852
```
834
853
854
+
모던 C++에서는 의미 있는 이름을 가진 `struct`가 더 일반적이다. 예를 들어 `ranges::min_max_result`, `from_chars_result` 등을 참조하라.
855
+
835
856
##### Exception
836
857
837
858
때에 따라서는 개체의 상태를 변경하기 위해 함수에 개체를 전달해야 할 수도 있다.
@@ -856,16 +877,18 @@ C++ 17에서는 다수의 변수들을 선언과 동시에 초기화 할 수 있
856
877
비교를 위해, 값을 반환하는 방법으로 해결한다면 아래와 같이 작성하게 될 것이다:
857
878
858
879
```c++
859
-
pair<istream&, string> get_string(istream& is); // not recommended
get_string_result get_string(istream& in) // not recommended
860
883
{
861
884
string s;
862
-
is >> s;
863
-
return {is, s};
885
+
in >> s;
886
+
return { in, move(s) };
864
887
}
865
888
866
-
for (auto p = get_string(cin); p.first; ) {
867
-
// do something with p.second
868
-
}
889
+
for (auto[in, s] = get_string(cin); in; s = get_string(in).s) {
890
+
// do something with string
891
+
}
869
892
```
870
893
871
894
생각보다 아름답지 않고 성능에도 좋지 않다.
@@ -892,11 +915,73 @@ C++ 17에서는 다수의 변수들을 선언과 동시에 초기화 할 수 있
892
915
893
916
추상화가 아닌 독립적인 존재들(independent entities)을 표현할 때는 `pair`와 `tuple`은 필요 이상으로 범용적(overly-generic)일 수 있다.
894
917
895
-
다른 예로는, `tuple`대신 특정 타입과 비슷한 `variant<T, error_code>`를 사용하라.
918
+
다른 옵션은 `pair`와 `tuple`이 아닌 `optional<T>` 또는 `expected<T, error_code>`를 사용하는 것이다. 적절하게 사용될 때 이러한 타입은 `pair<T, bool>` 또는 `pair<T, error_code>`보다 멤버들의 의도에 대한 더 많은 정보를 전달한다.
919
+
920
+
##### Note
921
+
922
+
반환할 개체가 복사 비용이 많이 드는 지역 변수에서 초기화되는 경우 명시적인 `move`가 복사를 피하는 데 도움이 될 수 있다:
0 commit comments