Simplest way to get memory size of std::array's underlying array?

Viewed 2071

Is this the simplest/shortest way to get size in memory of the content of what std::array::data() returns?

arr.size() * sizeof(arr.value_type)

Edit: My question wasn't precise. By "size in memory" I mean size of all elements (themselves) contained in the array so if e.g. they are pointers pointing to structures, I want the size of the pointers alone, not the structures pointed to. I also don't want to include the size of any possible overhead of the std::arr implementation. Just the array elements.

Some people suggested sizeof(arr). This: What is the sizeof std::array<char, N>? begs to disagree. And while it seems to work on my machine I want to know what the standard guarantees.

6 Answers

You can use the sizeof operator directly on your std::array instance:

sizeof(arr)

Example:

struct foo
{
    int a;
    char b;
};

int main()
{
    std::array<foo, 10> a;
    static_assert(sizeof(foo) == 8);
    static_assert(sizeof(a) == 80);
}

live example on wandbox


From cppreference:

std::array is a container that encapsulates fixed size arrays.

This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member.

There's no guarantee that sizeof(std::array<T,N>) == N*sizeof(T), but it is guaranteed that sizeof(std::array<T,N>) >= N*sizeof(T). The extra size might be named (but unspecified) members and/or unnamed padding.

The guarantee follows from the fact that the wrapped T[N] array must be the first member of std::array<T,N>, but other members aren't specified.

Since no one has posted anything better than my first guess in question and sizeof(arr) is most likely NOT guaranteed to not include the size of any possible additional std::array's fields I'm choosing this as the accepted answer.

arr.size() * sizeof(arr.value_type)

Should anyone come up with anything better I'd be happy to accept their answer instead.

I have understood that you were asking: what is the size of the memory occupied by the ensemble of the element of an array<value_type,N> arr, that is between arr.begin() and arr.end()?

The answer is sizeof(value_type)*N, this is stated in the standard, but it needs some processing to get to this conclusion.

In the C++ standard [dcl.array] (this is about (c-)array not std::array):

An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.

in [expr.add] (here also term array refers to (c-)array):

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements, 86 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤ n; otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j ≤ n; otherwise, the behavior is undefined.

And in [array.data] (here the term array refers to std::array):

constexpr T* data() noexcept;
constexpr const T* data() const noexcept;

Returns: A pointer such that data() == addressof(front()), and [data(), data() + size()) is a valid range.

So data() return a valid range to the element of the std::array, this range is iterable using a pointer to the value_type, so it follows pointer arithmetic which follows rule for (c-)array indexing, and elements of a (c-)array are contiguous. Q.E.D.

I think you have to restort to using a helper function like

template <typename T>
auto getSize(T& t) -> size_t {
    typename T::size_type size = t.size();
    size_t value_type_size = sizeof(typename T::value_type);

    return size * value_type_size;
}

Read documentation of std::array. So yes, it probably is. Or try perhaps

  (arr.size()-1) * sizeof(arr.value_type) + sizeof(std::array<T,1>)

But I would just use sizeof(arr)

BTW, I am not sure that you have any formal guarantee about that. I guess that the standard would theoretically allow std::array to be the same as std::vector, except that resize() and some other methods would be hidden. But no sane implementation would do that (since std::array has been invented to pack plain arrays in a container similar to vectors).

Perhaps an implementation which only allow std::array-s of at most two elements (but throw some exception otherwise) could be conforming to the letter of the standard.

Related