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

7

10

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.

Angele answered 27/9, 2017 at 13:4 Comment(7)
Is that supposed to be a self-answered question?Orthochromatic
Why not just sizeof arr?Orthochromatic
Just try sizeof(arr)Actualize
@Orthochromatic It's not supposed to be anything. The suggested way of calculating the memory size is my best guess but I don't know if it's the best one (or even correct). Also everyone please see my edit.Angele
Do you want to include or exclude padding?Orthochromatic
@Orthochromatic Does padding occur in raw arrays? Because I want the same behaviour as for sizeof(my_raw_array).Angele
@nwp, no C arrays cannot have padding ( that is, the size of T[N] is always sizeof(T)*N ), the standard says so explicitly. Of course T can have padding in itself, a struct holding a T[N] also can ...Subservient
A
2

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.

Angele answered 29/9, 2017 at 11:48 Comment(3)
@Moberg Wow, this was so long ago. I don't even remember why I didn't accept it then (maybe SO doesn't allow it right away and then I forgot?). Anyway, fixed. Thanks.Angele
:D (it 's not enough to post a happy face so I have to write something more)Wardieu
My compiler didn't like the . with a type. However it was fine with arr.size() * sizeof(decltype(arr)::value_type)/Incendiarism
C
6

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.

Coaster answered 27/9, 2017 at 13:7 Comment(8)
And is it guaranteed that sizeof(struct{T t[N];}) == N * sizeof(T)? (especially, does sizeof(std::array<char,3>) == 3?)Listen
@YSC, even if it were ( and I don't think so ) it's far from obvious that "having the same semantics" implies having the same size ( a simple counterexample being std::array<T,0> ).Subservient
@MassimilianoJanes While your counterexample might be considered a special case and I'd be willing to look past it, like I mentioned in the edit to my post apparently sizeof isn't the way to go at all.Angele
@NPS: I don't understand - you want to know how much memory the array is occupying, right? If so, sizeof is the way to go, because it will tell you exactly the amount of memory occupied by your std::array instance, even if it's different from T*size.Coaster
@NPS: if you want to know what T*size is and don't care about the std::array... just do sizeof(T) * N.Coaster
I want to know the size of whatever data() returns. As for your 2nd comment - that's exactly what I wrote in my question but I'd like to know if that's the simplest way I can do it.Angele
I find it worrying that there are two excluding answers on stack both getting upvotes. I'm referring to the answer linked in my question of course.Angele
@NPS: "I want to know the size of whatever data() returns" - sizeof(arr.data()) ?Coaster
S
3

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.

Spartacus answered 27/9, 2017 at 13:53 Comment(3)
std::array is an aggregate that doesn't have a std::initializer_list constructor (uses list/aggregate initialization), so the only non-static member it has is the C-Style array, meaning that there shouldn't be any other unspecified members.Judi
@AndyG: Other unspecified members would be initialized to 0, nullptr or false, wouldn't they? Aggregate initialization does not need to provide initializers for all members.Spartacus
I suppose you're right. The quote from cppreference tripped me up. (Same semantics as a struct holding a Cstyle array does not imply in reality it only holds a cstyle array, only that the cstyle array needs to be first)Judi
A
2

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.

Angele answered 29/9, 2017 at 11:48 Comment(3)
@Moberg Wow, this was so long ago. I don't even remember why I didn't accept it then (maybe SO doesn't allow it right away and then I forgot?). Anyway, fixed. Thanks.Angele
:D (it 's not enough to post a happy face so I have to write something more)Wardieu
My compiler didn't like the . with a type. However it was fine with arr.size() * sizeof(decltype(arr)::value_type)/Incendiarism
S
0

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.

Seldan answered 27/9, 2017 at 16:29 Comment(5)
No, I asked "what is the simplest way of getting that size."Angele
I thought you were asking if the standard guarantee that this size is arr.size()*sizeof(arr_type::value_type). I am not sure of what mean "simplest" for you, but arr.size()*sizeof(arr_type::value_type) is a constant expression: it is evaluated at compile time, it does not generate any code.Seldan
I meant the simplest code, so the less writing/calculating the better.Angele
0 for exec, some for the dev. And the more complicated the code the higher chance of doing something wrong. Simpler code creates less bugs. It's also easier to remember and faster to write.Angele
@Angele I am adhering to this point of view. Nevertheless, when there are no better alternatives, there are no better choice!Seldan
C
0

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;
}
Champlain answered 4/2, 2021 at 9:45 Comment(0)
I
0

If value_type gets tricky (because you need sizeof(decltype(var)::value_type) for the member size) then there's always the data() type.

std::array<int, 12> var;
size_var = sizeof(*var.data()) * var.size();
std::cout << size_var << std::endl;

which outputs "48" on my machine.

Incendiarism answered 17/10, 2023 at 1:4 Comment(0)
M
-1

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.

Mothy answered 27/9, 2017 at 13:58 Comment(1)
How can you have the same layout as vector (i.e. values stored in dynamically allocated memory) while retaining the aggregate initialization of std::array ?Spartacus

© 2022 - 2024 — McMap. All rights reserved.