const std::array<T,N>和std::array<const T, N>之间的区别

46

std::array<const T, N>const std::array<T, N>之间有实际区别吗?

看起来,持有常量元素的非const数组仍然无法交换;赋值运算符也不起作用。

在什么情况下应该优先考虑其中之一?

#include <array>

std::array<const int, 5> array_of_const = {1,2,3,4,5};
std::array<const int, 5> array_of_const2 = {1,2,3,4,5};

const std::array<int, 5> const_array = {1,2,3,4,5};
const std::array<int, 5> const_array2 = {1,2,3,4,5};

int main()
{
    // Assignment doesn't work for either
    array_of_const = array_of_const2;
    const_array = const_array2;

    // Swapping doesn't work for either
    array_of_const.swap(array_of_const2);
    const_array.swap(const_array2);

    // Indexing...
    array_of_const[0] = 0;
    const_array[0] = 0;

    return 0;
};

3
@DrewDormann 是的,我同意。我想不出任何好的理由来支持这些。 - Paul Sanders
2
@KarlKnechtel [language-lawyer] 实际上并未被 OP 添加。 - apple apple
1
我不明白为什么这个帖子有那么多赞(最初的大部分可能是平衡投票,我认为这很糟糕)。 - apple apple
2
@ildjarn 什么是“巨大、明显的实际差异”?我没有看到任何差异。 - Caleth
2
@wooc 在 ildjarn 的辩护中,这并不是最清晰的例子。我最初也认为它在指出一个差异。 - JohnFilleau
显示剩余3条评论
3个回答

41

std::array<const T, N>的副本仍然是“逻辑上常量”,而默认情况下,const std::array<T, N>的副本是可变的。如果允许或防止这种情况对您很重要,那么其中一种方法比另一种更可取。

它们匹配模板的方式有所不同,例如在Ilya的答案中的情况。


22

可能至少有一个区别 - 当你需要将变量传递给其他函数时,例如:

#include <array>

std::array<const int, 5> cc_arr5 = {1,2,3,4,5};
const std::array<int, 5> cc_arr5_2 = {1,2,3,4,5};

template<class T, std::size_t N>
void func(std::array<T, N>& a) {
    // do not change a, for example just calculate sum
}

int main()
{
    func(cc_arr5);
    func(cc_arr5_2); // this line does not compile

    return 0;
};

2
好的,即使是刻意制造的差异,也存在差异。尽管我们在实际中看到过一些函数接收非 const 引用,但实际上并没有改变参数,所以我猜这不算特别刻意了。 - JohnFilleau
1
正好是我要发布的例子...因为你比我快几分钟,所以给你一些独角兽分数。 - Adrian Mole
1
考虑通过展示在函数体中a不需要被改变才能使其工作,来扩展这个例子?https://godbolt.org/z/qqPc9qW77 - JohnFilleau
@JohnFilleau 是的,已添加注释。 - Iłya Bursov
2
当然,通过值传递std::span比通过引用传递std::array或本地数组要好得多... - Deduplicator
1
现在唯一缺少的就是一个 const std:array<const int, 5> 的示例。 - tommsch

9

它们确实是不同的类型,因此您不能在期望另一个类型的地方使用其中之一,例如在函数调用或赋值中。

话虽如此,由于数组是一个没有辅助数据成员且大小固定的容器,将容器声明为const可以防止对其元素进行任何更改,将元素声明为const也不允许对容器进行任何更改,因为显然它没有其他数据成员。

换句话说,这两种类型将具有完全相同的有效操作和无效操作。

我能想到的主要区别是 const_cast 的含义:数组可以(隐式)转换为相同元素类型的const数组,但不能转换为被const修饰的数组类型:

std::array<int, 3> a {1, 2, 3};

std::array<const int, 3> b = a; // Error: no known conversion from 'array<int, [...]>' to 'const array<const int, [...]>
const std::array<int, 3> c = a; // Ok

1
也许有两个const_cast的含义:其中一个类型也可以去掉const - Drew Dormann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接