왜 대괄호를 사용하여 목록 초기화가 대안보다 낫습니까?
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
왜?
SO에 대한 답변을 찾을 수 없으므로 내 질문에 대답하겠습니다.
Bjarne Stroustrup의 "The C ++ Programming Language 4th Edition" 에서 기본적으로 복사하여 붙여 넣기 :
리스트 초기화 는 축소를 허용하지 않습니다 (§iso.8.5.4). 그건:
- 정수는 값을 보유 할 수없는 다른 정수로 변환 할 수 없습니다. 예를 들어, char to int는 허용되지만 int to char는 허용되지 않습니다.
- 부동 소수점 값은 해당 값을 보유 할 수없는 다른 부동 소수점 유형으로 변환 할 수 없습니다. 예를 들어, float to double은 허용되지만 double to float는 허용되지 않습니다.
- 부동 소수점 값은 정수 유형으로 변환 할 수 없습니다.
- 정수 값은 부동 소수점 유형으로 변환 할 수 없습니다.
예:
void fun(double val, int val2) {
int x2 = val; // if val==7.9, x2 becomes 7 (bad)
char c2 = val2; // if val2==1025, c2 becomes 1 (bad)
int x3 {val}; // error: possible truncation (good)
char c3 {val2}; // error: possible narrowing (good)
char c4 {24}; // OK: 24 can be represented exactly as a char (good)
char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)
int x4 {2.0}; // error: no double to int value conversion (good)
}
에만 사용하는 경우 =이보다 선호되는 상황은 {}이다 auto
이니셜 라이저에 의해 결정 유형을 얻기 위해 키워드를.
예:
auto z1 {99}; // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int
결론
강력한 이유가없는 한 대체 방법보다 {} 초기화를 선호하십시오.
목록 초기화를 사용하는 이점에 대해서는 이미 큰 대답이 있지만 개인적으로 경험할 때마다 중괄호를 사용하지 말고 개념적 의미에 의존하게하십시오.
- 내가 만들고있는 객체가 개념적으로 생성자에 전달하는 값 (예 : 컨테이너, POD 구조체, 원자, 스마트 포인터 등)을 보유하고 있다면 중괄호를 사용하고 있습니다.
- 생성자가 일반 함수 호출과 비슷하면 (인수로 매개 변수가있는 다소 복잡한 작업을 수행합니다) 정상적인 함수 호출 구문을 사용하고 있습니다.
- 기본 초기화에는 항상 중괄호를 사용합니다.
하나, 그 방법으로 나는 항상 예를 들어 어쨌든 내장 / POD 유형이라고 불리는 기본 생성자가있는 "실제"클래스인지 여부에 관계없이 객체가 초기화되는지 확신합니다. 둘째, 기본 초기화 객체는 종종 "빈"객체를 나타 내기 때문에 대부분의 경우 첫 번째 규칙과 일치합니다.
필자의 경험에 따르면이 규칙 세트는 기본적으로 중괄호를 사용하는 것보다 훨씬 일관되게 적용될 수 있지만 괄호가있는 "일반"함수 호출 구문과 다른 의미를 사용할 수 없거나 다른 의미가있는 경우 모든 예외를 명시 적으로 기억해야합니다. (다른 과부하를 호출).
예를 들어 std::vector
다음 과 같은 표준 라이브러리 유형에 잘 맞습니다 .
vector<int> a{10,20}; //Curly braces -> fills the vector with the arguments
vector<int> b(10,20); //Parenthesis -> uses arguments to parametrize some functionality,
vector<int> c(it1,it2); //like filling the vector with 10 integers or copying a range.
vector<int> d{}; //empty braces -> default constructs vector, which is equivalent
//to a vector that is filled with zero elements
이 사용 중괄호 초기화에 대한 많은 이유가 있습니다,하지만 당신은 알고 있어야합니다 생성자가 다른 생성자 선호된다 예외가 기본적으로 생성자 것. 이로 인해 형식 생성자가 초기화 목록이거나 일반 오래된 ctor가 될 수있는 생성자와 템플릿에 문제가 발생 합니다.initializer_list<>
T
struct Foo {
Foo() {}
Foo(std::initializer_list<Foo>) {
std::cout << "initializer list" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy ctor" << std::endl;
}
};
int main() {
Foo a;
Foo b(a); // copy ctor
Foo c{a}; // copy ctor (init. list element) + initializer list!!!
}
이러한 클래스가 발생하지 않는다고 가정하면 초기화 프로그램 목록을 사용하지 않는 이유는 거의 없습니다.
Google이 Chromium에서 말하는 것처럼 좁지 않은 빌드로 빌드하지 않는 한 더 안전합니다. 그렇게하면 덜 안전합니다.
참고 : A) 괄호는 좁아지지 않기 때문에 더 안전합니다. B) 꼬부라 진 사람은 개인 생성 자나 삭제 된 생성자를 무시하고 명시 적으로 표시된 생성자를 암시 적으로 호출 할 수 있기 때문에 안전하지 않습니다.
이 두 가지 결합은 내부의 것이 기본 상수이면 더 안전하지만 객체이면 안전하지 않다는 것을 의미합니다.
'Programming' 카테고리의 다른 글
"자동"대 "자동 (지연된 시작)" (0) | 2020.03.03 |
---|---|
ASP.NET MVC 뷰 엔진 비교 (0) | 2020.03.03 |
YAML에서 문자열에 대한 따옴표가 필요합니까? (0) | 2020.03.03 |
새로운 대신 alloc init 사용 (0) | 2020.03.03 |
파일 경로에서 파일 디렉토리 경로 가져 오기 (0) | 2020.03.02 |