중괄호로 묶인 이니셜 라이저는 언제 사용합니까?
C ++ 11에는 클래스 초기화를위한 새로운 구문이있어 변수를 초기화하는 방법에 대한 많은 가능성을 제공합니다.
{ // Example 1
int b(1);
int a{1};
int c = 1;
int d = {1};
}
{ // Example 2
std::complex<double> b(3,4);
std::complex<double> a{3,4};
std::complex<double> c = {3,4};
auto d = std::complex<double>(3,4);
auto e = std::complex<double>{3,4};
}
{ // Example 3
std::string a(3,'x');
std::string b{3,'x'}; // oops
}
{ // Example 4
std::function<int(int,int)> a(std::plus<int>());
std::function<int(int,int)> b{std::plus<int>()};
}
{ // Example 5
std::unique_ptr<int> a(new int(5));
std::unique_ptr<int> b{new int(5)};
}
{ // Example 6
std::locale::global(std::locale("")); // copied from 22.4.8.3
std::locale::global(std::locale{""});
}
{ // Example 7
std::default_random_engine a {}; // Stroustrup's FAQ
std::default_random_engine b;
}
{ // Example 8
duration<long> a = 5; // Stroustrup's FAQ too
duration<long> b(5);
duration<long> c {5};
}
선언하는 각 변수에 대해 어떤 초기화 구문을 사용해야하는지 생각해야하는데 이로 인해 코딩 속도가 느려집니다. 나는 그것이 중괄호를 도입하려는 의도가 아니라고 확신합니다.
템플릿 코드와 관련하여 구문을 변경하면 다른 의미로 이어질 수 있으므로 올바른 방법으로가는 것이 필수적입니다.
어떤 구문을 선택해야하는지 보편적 인 지침이 있는지 궁금합니다.
나는 생각 다음이 좋은 지침이 될 수 :
초기화하는 (단일) 값이 객체 의 정확한 값 이되도록 의도 된 경우 복사 (
=
) 초기화를 사용합니다 (오류가 발생해도 실수로 명시 적 생성자를 호출하지 않으므로 일반적으로 제공된 값을 해석합니다.) 다르게). 복사 초기화를 사용할 수없는 곳에서는 중괄호 초기화에 올바른 의미가 있는지 확인하고, 그렇다면이를 사용합니다. 그렇지 않으면 괄호 초기화를 사용합니다 (사용할 수없는 경우 어쨌든 운이 없습니다).초기화하는 값이 객체에 저장할 값 목록 (예 : 벡터 / 배열의 요소 또는 복소수의 실수 / 허수 부분) 인 경우 가능한 경우 중괄호 초기화를 사용합니다.
If the values you are initializing with are not values to be stored, but describe the intended value/state of the object, use parentheses. Examples are the size argument of a
vector
or the file name argument of anfstream
.
I am pretty sure there will never be a universal guideline. My approach is to use always curly braces remembering that
- Initializer list constructors take precedence over other constructors
- All standard library containers and std::basic_string have initializer list constructors.
- Curly brace initialization does not allow narrowing conversions.
So round and curly braces are not interchangeable. But knowing where they differ allows me to use curly over round bracket initialization in most cases (some of the cases where I can't are currently compiler bugs).
Outside of generic code (i.e. templates), you can (and I do) use braces everywhere. One advantage is that it works everywhere, for instance even for in-class initialization:
struct foo {
// Ok
std::string a = { "foo" };
// Also ok
std::string b { "bar" };
// Not possible
std::string c("qux");
// For completeness this is possible
std::string d = "baz";
};
or for function arguments:
void foo(std::pair<int, double*>);
foo({ 42, nullptr });
// Not possible with parentheses without spelling out the type:
foo(std::pair<int, double*>(42, nullptr));
For variables I don't pay much attention between the T t = { init };
or T t { init };
styles, I find the difference to be minor and will at worst only result in a helpful compiler message about misusing an explicit
constructor.
For types that accept std::initializer_list
though obviously sometimes the non-std::initializer_list
constructors are needed (the classical example being std::vector<int> twenty_answers(20, 42);
). It's fine to not use braces then.
When it comes to generic code (i.e. in templates) that very last paragraph should have raised some warnings. Consider the following:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{ return std::unique_ptr<T> { new T { std::forward<Args>(args)... } }; }
Then auto p = make_unique<std::vector<T>>(20, T {});
creates a vector of size 2 if T
is e.g. int
, or a vector of size 20 if T
is std::string
. A very telltale sign that there is something very wrong going on here is that there's no trait that can save you here (e.g. with SFINAE): std::is_constructible
is in terms of direct-initialization, whereas we're using brace-initialization which defers to direct-initialization if and only if there's no constructor taking std::initializer_list
interfering. Similarly std::is_convertible
is of no help.
I've investigated if it is in fact possible to hand-roll a trait that can fix that but I'm not overly optimistic about that. In any case I don't think we would be missing much, I think that the fact that make_unique<T>(foo, bar)
result in a construction equivalent to T(foo, bar)
is very much intuitive; especially given that make_unique<T>({ foo, bar })
is quite dissimilar and only makes sense if foo
and bar
have the same type.
Hence for generic code I only use braces for value initialization (e.g. T t {};
or T t = {};
), which is very convenient and I think superior to the C++03 way T t = T();
. Otherwise it's either direct initialization syntax (i.e. T t(a0, a1, a2);
), or sometimes default construction (T t; stream >> t;
being the only case where I use that I think).
That doesn't mean that all braces are bad though, consider the previous example with fixes:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{ return std::unique_ptr<T> { new T(std::forward<Args>(args)...) }; }
This still uses braces for constructing the std::unique_ptr<T>
, even though the actual type depend on template parameter T
.
참고URL : https://stackoverflow.com/questions/9976927/when-to-use-the-brace-enclosed-initializer
'program tip' 카테고리의 다른 글
Numpy 배열의 열을 반복하는 방법은 무엇입니까? (0) | 2020.09.07 |
---|---|
distutils를 사용하여 설치된 Python 패키지를 어떻게 제거합니까? (0) | 2020.09.06 |
클로저는 언제 Fn, FnMut 및 FnOnce를 구현합니까? (0) | 2020.09.06 |
Windows Phone 7 에뮬레이터에서 TextBox.TextChanged 이벤트가 두 번 발생합니다. (0) | 2020.09.06 |
Python UTC datetime 객체의 ISO 형식에는 Z (Zulu 또는 Zero 오프셋)가 포함되지 않습니다. (0) | 2020.09.06 |