programing

C++에서 배열의 모든 요소를 하나의 기본값으로 초기화하시겠습니까?

instargram 2023. 5. 22. 20:19
반응형

C++에서 배열의 모든 요소를 하나의 기본값으로 초기화하시겠습니까?

C++ 참고: 배열 초기화에는 배열 초기화보다 좋은 목록이 있습니다.나는 있습니다

int array[100] = {-1};

값이 -1로 가득 차 있을 것으로 예상되지만, 첫 번째 값만 가득 차 있고 나머지 값은 0과 랜덤 값이 혼합되어 있습니다.

코드

int array[100] = {0};

각 요소를 0으로 설정하여 정상적으로 작동합니다.

여기서 내가 놓치고 있는 것은..값이 0이 아니면 초기화할 수 없습니까?

그리고 2: 기본 초기화(위와 같이)가 전체 어레이를 통과하는 일반적인 루프보다 빠르며 값을 할당합니까? 아니면 동일한 작업을 수행합니까?

당신이 사용한 구문을 사용하면,

int array[100] = {-1};

says 는 첫 번째 를 " 첫번째요소다설로정다니합으"로 설정합니다.-1그리고 나머지는0생략된 모든 요소가 다음으로 설정되어 있기 때문에0.

C++에서 모든 것을 다음으로 설정합니다.-1당신은 (에서)와 같은 것을 사용할 수 있습니다.<algorithm>):

std::fill_n(array, 100, -1);

휴대용 C에서, 당신은 당신 자신의 루프를 굴려야 합니다.컴파일러 확장이 있거나 구현 정의 동작을 바로 가기로 사용할 수 있습니다.

gcc 컴파일러에는 다음과 같은 구문을 허용하는 확장자가 있습니다.

int array[100] = { [0 ... 99] = -1 };

이렇게 하면 모든 요소가 -1로 설정됩니다.

이를 "지정된 초기화자"라고 합니다. 자세한 내용은 여기를 참조하십시오.

이것은 gcc c++ 컴파일러에서는 구현되지 않습니다.

연결한 페이지는 이미 첫 번째 부분에 대한 답을 제공했습니다.

명시적 배열 크기가 지정되었지만 더 짧은 초기화 목록이 지정된 경우 지정되지 않은 요소는 0으로 설정됩니다.

전체 배열을 0이 아닌 값으로 초기화하는 기본 제공 방법은 없습니다.

어떤 것이 더 빠른지에 대해서는 일반적인 규칙이 적용됩니다: "컴파일러에게 가장 많은 자유를 주는 방법은 아마도 더 빠를 것입니다."

int array[100] = {0};

컴파일러가 자유롭게 최적화할 수 있는 "이 100 ints를 0으로 설정"하는 것을 컴파일러에게 알려줍니다.

for (int i = 0; i < 100; ++i){
  array[i] = 0;
}

훨씬 더 구체적입니다.컴파일러에게 반복 변수를 생성하도록 지시합니다.i요소를 초기화해야 하는 순서 등을 알려줍니다.물론 컴파일러는 이 방법을 최적화할 가능성이 높지만 요점은 여기서 문제를 지나치게 지정하여 컴파일러가 동일한 결과를 얻기 위해 더 열심히 작업하도록 강요한다는 것입니다.

값으로 하려면 (에서는) 마막이로 0닌아값설면 (C++에서는) 지사를을 std::fill:

std::fill(array, array+100, 42); // sets every value in the array to 42

다시 말하지만 배열에서도 동일한 작업을 수행할 수 있지만, 이 작업은 더 간결하고 컴파일러에게 더 많은 자유를 제공합니다.당신은 단지 전체 배열이 42 값으로 채워지기를 원한다고 말하는 것입니다.당신은 그것이 어떤 순서로 이루어져야 하는지 또는 다른 어떤 것에 대해서도 말하지 않습니다.

C++11에는 다음과 같은 다른 (불완전한) 옵션이 있습니다.

std::array<int, 100> a;
a.fill(-1);

용사를 합니다.std::array우리는 이것을 C++14에서 꽤 간단한 방법으로 할 수 있습니다.C++11에서만 가능하지만 조금 더 복잡합니다.

우리의 인터페이스는 컴파일 시간 크기이며 기본값입니다.

template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
    return std::array<std::decay_t<T>, 0>{};
}

template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
    return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}


template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
    return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}

를 위한 가 직접 .std::integral_constant<std::size_t, size>그들 스스로, 그것은 꽤 말이 많은 구조이기 때문입니다.실제 작업은 처음 두 가지 기능 중 하나에 의해 수행됩니다.

간단합니다: " 번째과는매간니다단합우첫하부다니▁the합간단첫▁is".은 를구니다합을 건설합니다.std::array0 사이즈의복사할 필요는 없습니다. 우리는 그것을 구성할 뿐입니다.

두 번째 과부하는 조금 더 까다롭습니다.하고, 소로얻 값은따전며달되라구, 또인스를성다니합의 를 구성합니다.make_index_sequence그리고 다른 구현 함수를 호출합니다.그 기능은 어떻게 생겼습니까?

namespace detail {

template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
    // Use the comma operator to expand the variadic pack
    // Move the last element in if possible. Order of evaluation is well-defined
    // for aggregate initialization, so there is no risk of copy-after-move
    return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}

}   // namespace detail

전달한 값을 복사하여 첫 번째 size - 1 인수를 생성합니다.여기서는 변수 매개 변수 팩 인덱스를 확장할 대상으로 사용합니다.팩에는 - 이 들어 (「 」「 」「 - 1 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」「 」 「 」 「 」 「 」 「 」 「 」「make_index_sequence은 0, 2, ..., - 2 0, 1, 2, 3, ..., 크 - 2입입니다.그러나 값은 신경 쓰지 않습니다(따라서 컴파일러 경고를 잠재우기 위해 무효로 설정했습니다).매개 변수 팩 확장은 코드를 다음과 같은 수준으로 확장합니다(확장 크기 == 4).

return std::array<std::decay_t<T>, 4>{ (static_cast<void>(0), value), (static_cast<void>(1), value), (static_cast<void>(2), value), std::forward<T>(value) };

는 이러한 팩 합니다....원하는 항목을 확장하고 쉼표 연산자를 사용하도록 보장합니다.괄호가 없으면 배열 초기화에 많은 인수를 전달하는 것처럼 보이지만 실제로는 인덱스를 평가하고, 빈 결과를 무시하고, 빈 결과를 무시하고, 값을 반환합니다. 이 값은 배열에 복사됩니다.

가 막지논쟁, 가부르것는라고 부르는 std::forward은최적화입니다. on, 은 에서 사용됩니다.누군가 임시 std:: 문자열을 전달하고 "이것들 중 5개의 배열을 만들어라"라고 말하면, 우리는 5개의 복사본 대신 4개의 복사본과 1개의 이동을 원합니다.std::forward우리가 이 일을 할 수 있도록 보장합니다.

헤더 및 일부 장치 테스트를 포함한 전체 코드:

#include <array>
#include <type_traits>
#include <utility>

namespace detail {

template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
    // Use the comma operator to expand the variadic pack
    // Move the last element in if possible. Order of evaluation is well-defined
    // for aggregate initialization, so there is no risk of copy-after-move
    return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}

}   // namespace detail

template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
    return std::array<std::decay_t<T>, 0>{};
}

template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
    return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}

template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
    return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}



struct non_copyable {
    constexpr non_copyable() = default;
    constexpr non_copyable(non_copyable const &) = delete;
    constexpr non_copyable(non_copyable &&) = default;
};

int main() {
    constexpr auto array_n = make_array_n<6>(5);
    static_assert(std::is_same<std::decay_t<decltype(array_n)>::value_type, int>::value, "Incorrect type from make_array_n.");
    static_assert(array_n.size() == 6, "Incorrect size from make_array_n.");
    static_assert(array_n[3] == 5, "Incorrect values from make_array_n.");

    constexpr auto array_non_copyable = make_array_n<1>(non_copyable{});
    static_assert(array_non_copyable.size() == 1, "Incorrect array size of 1 for move-only types.");

    constexpr auto array_empty = make_array_n<0>(2);
    static_assert(array_empty.empty(), "Incorrect array size for empty array.");

    constexpr auto array_non_copyable_empty = make_array_n<0>(non_copyable{});
    static_assert(array_non_copyable_empty.empty(), "Incorrect array size for empty array of move-only.");
}

{}을(를) 사용하면 선언된 대로 요소를 할당하고 나머지 요소는 0으로 초기화됩니다.

없는 = {}초기화하기 위해 내용이 정의되지 않았습니다.

연결한 페이지의 상태

명시적 배열 크기가 지정되었지만 더 짧은 초기화 목록이 지정된 경우 지정되지 않은 요소는 0으로 설정됩니다.

파일: 할 수 .이렇게 작은 어레이의 경우 차이는 무시할 수 있습니다. 시 을 수 .memcpy수정 가능한 배열로 이동합니다.

배열을 공통 값으로 초기화하는 또 다른 방법은 다음과 같은 일련의 정의에서 요소 목록을 실제로 생성하는 것입니다.

#define DUP1( X ) ( X )
#define DUP2( X ) DUP1( X ), ( X )
#define DUP3( X ) DUP2( X ), ( X )
#define DUP4( X ) DUP3( X ), ( X )
#define DUP5( X ) DUP4( X ), ( X )
.
.
#define DUP100( X ) DUP99( X ), ( X )

#define DUPx( X, N ) DUP##N( X )
#define DUP( X, N ) DUPx( X, N )

어레이를 공통 값으로 쉽게 초기화할 수 있습니다.

#define LIST_MAX 6
static unsigned char List[ LIST_MAX ]= { DUP( 123, LIST_MAX ) };

참고: DUP에 대한 매개 변수의 매크로 대체를 활성화하기 위해 DUPx가 도입되었습니다.

단일 바이트 요소 배열의 경우 memset을 사용하여 모든 요소를 동일한 값으로 설정할 수 있습니다.

여기에 예가 있습니다.

가장 간단한 방법은 다음과 같습니다.std::array▁the▁that▁template▁ 반환하는 함수 템플릿을 작성합니다.std::array아래와 같이 전달된 인수로 모든 요소가 초기화됩니다.

C++11 버전

template<std::size_t N> std::array<int, N> make_array(int val)
{
    std::array<int, N> tempArray{};
    for(int &elem:tempArray)
    {
        elem = val;
    }
    return tempArray;
}
int main()
{
    //---------------------V-------->number of elements  
    auto arr  = make_array<8>(5);
    //------------------------^---->value of element to be initialized with

    
    //lets confirm if all objects have the expected value 
    for(const auto &elem: arr)
    {
        std::cout << elem << std::endl; //prints all 5 
    }
    
}

작업 데모


C++17 버전

C++17을 사용하여 추가할 수 있습니다.constexpr함수 템플릿으로 변환하여 constexpr 컨텍스트에서 사용할 수 있도록 합니다.

//-----------------------------------------vvvvvvvvv--->added constexpr
template<std::size_t N> std::array<int, N> constexpr make_array(int val)
{
    std::array<int, N> tempArray{};
    for(int &elem:tempArray)
    {
        elem = val;
    }
    return tempArray;
}
int main()
{
//--vvvvvvvvv------------------------------>constexpr added
    constexpr auto arr  = make_array<8>(5);

    for(const auto &elem: arr)
    {
        std::cout << elem << std::endl;
    }
    
}

작업 데모

이니셜라이저를 사용하는 경우 구조체 또는 배열에 대해 지정되지 않은 값이 기본적으로 생성됩니다.int와 같은 원시적인 유형의 경우, 그것은 그것들이 0이 될 것이라는 것을 의미합니다.이것은 재귀적으로 적용됩니다. 배열을 포함하는 구조체 배열을 가질 수 있으며 첫 번째 구조체의 첫 번째 필드만 지정하면 나머지는 모두 0 및 기본 생성자로 초기화됩니다.

컴파일러는 아마도 최소한 손으로 할 수 있는 것만큼 좋은 초기화 코드를 생성할 것입니다.저는 가능하면 컴파일러가 초기화를 해주는 것을 선호합니다.

C++ 프로그래밍 언어 V4에서 Stroustrup은 내장된 배열보다 벡터 또는 Valarray를 사용할 것을 권장합니다.Valarrary를 사용하면 생성할 때 다음과 같은 특정 값으로 초기화할 수 있습니다.

valarray <int>seven7s=(7777777,7);

어레이 7 멤버 길이가 "7777777"인 초기화.

이것은 "일반적인 오래된 C" 배열 대신 C++ 데이터 구조를 사용하여 답을 구현하는 C++ 방법입니다.

저는 코드에서 C++'isms v'isms를 사용하기 위해 valarray를 사용하는 것으로 전환했습니다.

언급URL : https://stackoverflow.com/questions/1065774/initialization-of-all-elements-of-an-array-to-one-default-value-in-c

반응형