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

yto*_*ano 3 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;
    }
};
Run Code Online (Sandbox Code Playgroud)

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

sky*_*ack 12

它说的更多,回复在你的报价中:

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

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

template<int N>
struct C {
    int size() { return N; }
};
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,这里我们做同样的事情并且N不会被保留,但它是一个模板参数,在编译时固定.

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

编辑(相应的评论)

当然,通过简单地调用其中一个方法,您无法在运行时更改此类数组的大小.如前所述这里:

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

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

但是,你有很多好处:

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

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

  • 实际上,长度是类型的一部分.这与C样式数组完全不同.使用这个数组,我不能用不同大小的数组替换它的值,因为它也可以是不同的类型. (2认同)

orl*_*rlp 7

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

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


Vla*_*cow 5

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

iterator begin() noexcept;
const_iterator begin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;
Run Code Online (Sandbox Code Playgroud)

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

例如这个循环

for (int i : arr)
    cout << i << endl
Run Code Online (Sandbox Code Playgroud)

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

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

正如类声明的那样

template <class T, size_t N >
struct array;
Run Code Online (Sandbox Code Playgroud)

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