C ++ 11数组如何不存储它的大小?

时间:2015-11-29 09:04:13

标签: c++ arrays c++11

来自cplusplus.com

  

在内部,数组不保留除其包含的元素之外的任何数据(甚至不是它的大小,这是一个模板参数,在编译时固定)。

我理解这意味着使用array类似于在同一范围内使用int[]sizeof。但这段代码是有效还是依赖于未定义的行为?

class A {
    array<int, 10> arr;
    void setArr() {
        for (int& i : arr)
            i = 42;
    }
    void printArr() {
        for (int i : arr)
            cout << i << endl;
    }
};

编译器如何知道何时停止foreach而不将数组大小存储在堆或堆栈上?我运行它,代码工作。

3 个答案:

答案 0 :(得分:12)

它说的更多,回复在你的引文中:

  

[...]甚至不是它的大小,这是一个模板参数,在编译时[...]

固定

例如,以下代码也是合法的:

template<int N>
struct C {
    int size() { return N; }
};

正如你所看到的,这里我们做同样的事情并且 N 无论如何都不会被保留,但它以模板参数而闻名,在编译时固定

同样适用于模板化的类std::array,它接受​​定义其大小的模板参数。因此, size 在编译时是已知的(并且是固定的),并且它隐式地是生成类型的一部分,即使在运行时没有保留额外的空间。

编辑(相应的评论)

当然,只需调用其中一个方法,就无法在运行时更改此类数组的大小。如上所述here

  

std :: array是一个封装固定大小数组的容器。

此外,动态更改其大小是没有意义的,因为它将不再与定义实际大小的模板参数保持一致。因此,响应很明显:没有,您无法更改其大小(当然,即使您可以使用该数组来填充具有不同大小的另一个数组)。

但是,你有很多好处:

  

该结构将C风格数组的性能和可访问性与标准容器的优点结合在一起,例如了解自己的大小,支持赋值,随机访问迭代器等。

由您决定是否值得使用它而不是简单的C风格数组。这主要取决于你所面临的问题,所以我不能这么说。

答案 1 :(得分:7)

当我们说std::array没有存储时,我们的意思是它不会保留内存以存储其大小运行

因为你说std::array<int, 10>,编译器知道数组的大小是10.所以它可以正确地实现std::array::end。使用它,基于范围的for循环知道何时停止。

答案 2 :(得分:5)

标准类std::array具有成员函数beginend,它们返回指向数组的第一个元素和最后一个实际元素之后的位置的迭代器。

iterator begin() noexcept;
const_iterator begin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;

当执行基于范围的for语句时,编译器会搜索该类的名称beginend,并使用它们来设置有效范围。

例如这个循环

for (int i : arr)
    cout << i << endl

实际上内部由编译器代替以下循环

for ( auto first = arr.begin(), last = arr.end(); first != last; ++first )
{
    int i = *first;
    cout << i << endl;
}

因为类被声明为

template <class T, size_t N >
struct array;

然后在类定义值N内,数组中的元素数量可被该类的其他成员接受,包括成员函数end()