Programming

왜 대괄호를 사용하여 목록 초기화가 대안보다 낫습니까?

procodes 2020. 3. 3. 23:06
반응형

왜 대괄호를 사용하여 목록 초기화가 대안보다 낫습니까?


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) 꼬부라 진 사람은 개인 생성 자나 삭제 된 생성자를 무시하고 명시 적으로 표시된 생성자를 암시 적으로 호출 할 수 있기 때문에 안전하지 않습니다.

이 두 가지 결합은 내부의 것이 기본 상수이면 더 안전하지만 객체이면 안전하지 않다는 것을 의미합니다.

참고 URL : https://stackoverflow.com/questions/18222926/why-is-list-initialization-using-curly-braces-better-than-the-alternatives



반응형