为什么std :: array没有构造函数,该构造函数需要使用要填充的数组的值?


77

是没有

std::array<T,size>::array(const T& value);

疏忽大意?对我来说似乎很有用,动态容器(如std::vector)确实具有类似的构造函数。

我完全知道

std::array<T,size>::fill(const T& value);

但这不是构造函数,并且内存将首先清零。如果我要所有人都-1这个家伙怎么办?


1
“然后首先将内存清零”您确定这是真的吗?
tohava

3
除非您要求,否则不会先将其清零。
R. Martinho Fernandes

1
除了所有答案的合计论证之外,还可能存在更具概念性的推理。填充构造函数可能会掩盖一个事实,即它实际上并不是在构造单个元素。它会首先调用聚合初始化,然后将值复制到元素中,它不能立即复制-构造元素(与a相比std::vector)。因此,由于它始终等同于array(); array.fill();,因此首先省略构造函数并不会掩盖这一事实。
Christian Rau

Answers:


54

std::array 根据设计,是一个聚合,因此没有用户声明的构造函数。

如您所说,可以fill在默认构造后使用。由于它是一个聚合,因此默认构造不会将内存归零,但会将其保留为未初始化(如果所包含的类型是可初始化的)。


1
所以这个页面错了吗?它明确表示该数组的元素是默认初始化的。
rubenvb

15
对于POD,默认初始化是no-init,对于我相信的所有其他东西,默认构造函数都是默认构造函数-取决于声明的点。
Xeo

1
@rubenvb:是的,它们将被默认初始化,而不是值初始化。因此,如果它们是可初始化的,那么它们将不被初始化。
Mike Seymour

是的。这仍然是标准IMO中非常顽皮的部分,它在用户类型和内置类型之间进行了区分:/
rubenvb

11
@rubenvb基本类型都具有普通的默认初始化。如果需要,用户定义的类型可以以相同的方式运行。那不是区别,而是一致性。
Casey

23

请注意,您可以利用数组未初始化为零且具有复制构造函数do的事实来有效地模拟这种构造函数。

template <size_t N, class T>
array<T,N> make_array(const T &v) {
    array<T,N> ret;
    ret.fill(v);
    return ret;
}

auto a = make_array<20>('z');

让我们不要使用不需要的模板参数来夸大呼叫站点;-)
rubenvb

4
char可以推断出来,所以您可以只写make_array<20>('z') 而不是make_array<20,char>('z')
Nawaz

@Nawaz哦,甚至更好。我应该问为什么没有make_array替代品:-)
rubenvb

1
@Walter:您无法返回任何形式的引用,因为您将返回对局部变量的引用。
GManNickG

3
T无法默认构造时,这是行不通的,那是您非常需要fill构造函数的时候。
克里斯·贝克

12

您可以std::index sequence为此使用:

namespace detail
{

    template <typename T, std::size_t...Is>
    constexpr std::array<T, sizeof...(Is)>
    make_array(const T& value, std::index_sequence<Is...>)
    {
        return {{(static_cast<void>(Is), value)...}};
    }
}

template <std::size_t N, typename T>
constexpr std::array<T, N> make_array(const T& value)
{
    return detail::make_array(value, std::make_index_sequence<N>());
}

演示版

std::make_index_sequence 是C ++ 14,但可以在C ++ 11中实现。

static_cast<void>(Is)是柄邪operator,T可能会提供。


3
这是最有用的答案,在T默认情况下不可构造时(即其他答案不足)时,也可以使用。
克里斯·贝克

1
@ChrisBeck完全不同意。对我而言,确实是这样,其他答案让我感到沮丧。用来表明投票不是全部。
乔纳斯·格里特曼

由于使用模板递归,因此无法针对大型数组进行编译。如果我需要一个没有默认构造函数的T的百万元素数组,那我很幸运吗?甚至C数组也对我有用。
—MichałBrzozowski

@MichałBrzozowski:std::index_sequence可以用对数实例化而不是线性来实现。并且编译器可能只具有“本征”来执行一个实例化。然后,不再有递归。
Jarod42 '19

1
@MichałBrzozowski:您仍然可以切换到std::vectorreserve整个大小并emplace_back循环访问。对于一百万个元素,由于实际内存有限,堆栈会出现问题。
Jarod42 '19

10

首先,它不是std::array<T>,它是std::array<T,N>这里N的编译时间常数积分表达式。

std::array是通过设计汇总。因此它没有任何东西使其无法聚合,这就是为什么它没有构造函数...以及析构函数,虚函数等的原因。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.