将数组的所有元素初始化为 C++ 中的一个默认值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1065774/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:39:21  来源:igfitidea点击:

Initialization of all elements of an array to one default value in C++?

c++arraysinitializationvariable-assignmentdefault-value

提问by Milan

C++ Notes: Array Initializationhas a nice list over initialization of arrays. I have a

C++ 注释:Array Initialization有一个很好的关于数组初始化的列表。我有一个

int array[100] = {-1};

expecting it to be full with -1's but its not, only first value is and the rest are 0's mixed with random values.

期望它充满 -1 但它不是,只有第一个值是,其余是 0 与随机值混合。

The code

编码

int array[100] = {0};

works just fine and sets each element to 0.

工作得很好,并将每个元素设置为 0。

What am I missing here.. Can't one initialize it if the value isn't zero ?

我在这里错过了什么.. 如果值不为零,就不能初始化它吗?

And 2: Is the default initialization (as above) faster than the usual loop through the whole array and assign a value or does it do the same thing?

和 2:默认初始化(如上)是否比通常的遍历整个数组并赋值的循环快,还是做同样的事情?

回答by Evan Teran

Using the syntax that you used,

使用您使用的语法,

int array[100] = {-1};

says "set the first element to -1and the rest to 0" since all omitted elements are set to 0.

说“将第一个元素设置为-1,其余0元素设置为”,因为所有省略的元素都设置为0.

In C++, to set them all to -1, you can use something like std::fill_n(from <algorithm>):

在 C++ 中,要将它们全部设置为-1,您可以使用类似std::fill_n(from <algorithm>) 的内容:

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

In portable C, you have to roll your own loop. There are compiler-extensions or you can depend on implementation-defined behavior as a shortcut if that's acceptable.

在便携式 C 中,您必须滚动自己的循环。有编译器扩展,或者如果可以接受,您可以依赖实现定义的行为作为快捷方式。

回答by Callum

There is an extension to the gcc compiler which allows the syntax:

gcc 编译器有一个扩展,它允许使用以下语法:

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

This would set all of the elements to -1.

这会将所有元素设置为 -1。

This is known as "Designated Initializers" see herefor further information.

这被称为“指定初始值设定项”,请参阅此处了解更多信息。

Note this isn't implemented for the gcc c++ compiler.

请注意,这不是为 gcc c++ 编译器实现的。

回答by jalf

The page you linked to already gave the answer to the first part:

您链接到的页面已经给出了第一部分的答案:

If an explicit array size is specified, but an shorter initiliazation list is specified, the unspecified elements are set to zero.

如果指定了显式数组大小,但指定了较短的初始化列表,则未指定的元素将设置为零。

There is no built-in way to initialize the entire array to some non-zero value.

没有内置方法可以将整个数组初始化为某个非零值。

As for which is faster, the usual rule applies: "The method that gives the compiler the most freedom is probably faster".

至于哪个更快,通常的规则适用:“给编译器最大自由的方法可能更快”。

int array[100] = {0};

simply tells the compiler "set these 100 ints to zero", which the compiler can optimize freely.

简单地告诉编译器“将这 100 个整数设置为零”,编译器可以自由优化。

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

is a lot more specific. It tells the compiler to create an iteration variable i, it tells it the orderin which the elements should be initialized, and so on. Of course, the compiler is likely to optimize that away, but the point is that here you are overspecifying the problem, forcing the compiler to work harder to get to the same result.

更具体。它告诉编译器创建一个迭代变量i,告诉它应该初始化元素的顺序,等等。当然,编译器很可能会优化它,但关键是你在这里过度指定了问题,迫使编译器更努力地工作以获得相同的结果。

Finally, if you want to set the array to a non-zero value, you should (in C++, at least) use std::fill:

最后,如果要将数组设置为非零值,则应该(至少在 C++ 中)使用std::fill

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

Again, you could do the same with an array, but this is more concise, and gives the compiler more freedom. You're just saying that you want the entire array filled with the value 42. You don't say anything about in which order it should be done, or anything else.

同样,你可以对数组做同样的事情,但这样更简洁,并且给了编译器更多的自由。你只是说你想要用值 42 填充整个数组。你没有说应该按什么顺序完成,或者其他任何事情。

回答by Timmmm

C++11 has another (imperfect) option:

C++11 有另一个(不完美的)选项:

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

回答by 0x6adb015

With {} you assign the elements as they are declared; the rest is initialized with 0.

使用 {},您可以在元素声明时对其进行分配;其余的初始化为 0。

If there is no = {}to initalize, the content is undefined.

如果没有= {}初始化,则内容未定义。

回答by laalto

The page you linked states

您链接的页面说明

If an explicit array size is specified, but an shorter initiliazation list is specified, the unspecified elements are set to zero.

如果指定了显式数组大小,但指定了较短的初始化列表,则未指定的元素将设置为零。

Speed issue: Any differences would be negligible for arrays this small. If you work with large arrays and speed is much more important than size, you can have a const array of the default values (initialized at compile time) and then memcpythem to the modifiable array.

速度问题:对于这么小的阵列,任何差异都可以忽略不计。如果您使用大型数组并且速度比大小重要得多,您可以拥有一个默认值的 const 数组(在编译时初始化),然后将memcpy它们添加到可修改的数组中。

回答by Steen

Another way of initializing the array to a common value, would be to actually generate the list of elements in a series of defines:

将数组初始化为公共值的另一种方法是实际生成一系列定义中的元素列表:

#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 )

Initializing an array to a common value can easily be done:

可以轻松地将数组初始化为公共值:

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

Note: DUPx introduced to enable macro substitution in parameters to DUP

注意:引入 DUPx 以启用 DUP 参数中的宏替换

回答by David Stone

Using std::array, we can do this in a fairly straightforward way in C++14. It is possible to do in C++11 only, but slightly more complicated.

使用std::array,我们可以在 C++14 中以一种相当简单的方式做到这一点。只能在 C++11 中完成,但稍微复杂一些。

Our interface is a compile-time size and a default value.

我们的接口是一个编译时大小和一个默认值。

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));
}

The third function is mainly for convenience, so the user does not have to construct a std::integral_constant<std::size_t, size>themselves, as that is a pretty wordy construction. The real work is done by one of the first two functions.

第三个功能主要是为了方便,所以用户不必std::integral_constant<std::size_t, size>自己构造一个,因为这是一个很罗嗦的构造。真正的工作是由前两个函数之一完成的。

The first overload is pretty straightforward: It constructs a std::arrayof size 0. There is no copying necessary, we just construct it.

第一个重载非常简单:它构造一个std::array大小为 0 的a 。不需要复制,我们只是构造它。

The second overload is a little trickier. It forwards along the value it got as the source, and it also constructs an instance of make_index_sequenceand just calls some other implementation function. What does that function look like?

第二个重载有点棘手。它沿着它作为源获得的值进行转发,并且它还构造了一个实例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

This constructs the first size - 1 arguments by copying the value we passed in. Here, we use our variadic parameter pack indexes just as something to expand. There are size - 1 entries in that pack (as we specified in the construction of make_index_sequence), and they have values of 0, 1, 2, 3, ..., size - 2. However, we do not care about the values (so we cast it to void, to silence any compiler warnings). Parameter pack expansion expands out our code to something like this (assuming size == 4):

这通过复制我们传入的值构造了第一个 size - 1 参数。在这里,我们使用可变参数包索引作为扩展。该包中有 size - 1 个条目(正如我们在 的构造中指定的那样make_index_sequence),它们的值为 0, 1, 2, 3, ..., size - 2。但是,我们不关心这些值(所以我们将其强制转换为 void,以消除任何编译器警告)。参数包扩展将我们的代码扩展成这样(假设大小 == 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) };

We use those parentheses to ensure that the variadic pack expansion ...expands what we want, and also to ensure we are using the comma operator. Without the parentheses, it would look like we are passing a bunch of arguments to our array initialization, but really, we are evaluating the index, casting it to void, ignoring that void result, and then returning value, which is copied into the array.

我们使用这些括号来确保可变参数包扩展...扩展我们想要的内容,并确保我们使用逗号运算符。如果没有括号,看起来我们将一堆参数传递给我们的数组初始化,但实际上,我们正在评估索引,将其转换为 void,忽略该 void 结果,然后返回值,该值被复制到数组中.

The final argument, the one we call std::forwardon, is a minor optimization. If someone passes in a temporary std::string and says "make an array of 5 of these", we would like to have 4 copies and 1 move, instead of 5 copies. The std::forwardensures that we do this.

我们呼吁的最后一个论点std::forward是一个小优化。如果有人传入一个临时的 std::string 并说“制作一个由 5 个组成的数组”,我们希望有 4 个副本和 1 个移动,而不是 5 个副本。在std::forward我们做这个保证。

The full code, including headers and some unit tests:

完整代码,包括标题和一些单元测试:

#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.");
}

回答by Steve Melnikoff

For the case of an array of single-byte elements, you can use memset to set all elements to the same value.

对于单字节元素数组的情况,您可以使用 memset 将所有元素设置为相同的值。

There's an example here.

这里有一个例子在这里

回答by ingomueller.net

In C++, it is also possible to use meta programming and variadic templates. The following post shows how to do it: Programmatically create static arrays at compile time in C++.

在 C++ 中,也可以使用元编程和可变参数模板。下面的文章展示了如何做到这一点:在 C++ 中以编程方式在编译时创建静态数组