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

新手上路,请多包涵

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

int array[100] = {-1};

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

编码

int array[100] = {0};

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

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

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

原文由 Milan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 768
2 个回答

使用您使用的语法,

 int array[100] = {-1};

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

在 C++ 中,要将它们全部设置为 -1 ,您可以使用 std::fill_n 类的东西(来自 <algorithm> ):

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

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

原文由 Evan Teran 发布,翻译遵循 CC BY-SA 3.0 许可协议

使用 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> ,因为这是一个相当罗嗦的构造。真正的工作是由前两个函数之一完成的。

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

第二个重载有点棘手。它沿着它作为源得到的值转发,它还构造了一个 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 参数。在这里,我们使用可变参数包索引作为扩展的东西。该包中有 size - 1 个条目(正如我们在 make_index_sequence 的构造中指定的那样),它们的值为 0、1、2、3、…、size - 2。但是,我们不关心这些值(所以我们将其强制转换为 void,以消除任何编译器警告)。参数包扩展将我们的代码扩展为如下所示(假设 size == 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) };

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

最后一个参数,我们称之为 std::forward on,是一个小的优化。如果有人传入一个临时的 std::string 并说“制作一个由 5 个组成的数组”,我们希望有 4 个副本和 1 个移动,而不是 5 个副本。 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.");
}

原文由 David Stone 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题