9

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.

NPS
  • 6,003
  • 11
  • 53
  • 90

6 Answers6

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.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 4
    And is it guaranteed that `sizeof(struct{T t[N];}) == N * sizeof(T)`? (especially, does `sizeof(std::array) == 3`?) – YSC Sep 27 '17 at 13:15
  • 1
    @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 ). – Massimiliano Janes Sep 27 '17 at 13:17
  • @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. – NPS Sep 27 '17 at 13:31
  • @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`. – Vittorio Romeo Sep 27 '17 at 13:49
  • 1
    @NPS: if you want to know what `T*size` is and don't care about the `std::array`... just do `sizeof(T) * N`. – Vittorio Romeo Sep 27 '17 at 13:50
  • 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. – NPS Sep 27 '17 at 13:56
  • 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. – NPS Sep 27 '17 at 14:48
  • @NPS: *"I want to know the size of whatever `data()` returns"* - `sizeof(arr.data())` ? – Vittorio Romeo Sep 27 '17 at 14:48
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.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 1
    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. – AndyG Sep 27 '17 at 14:08
  • @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. – MSalters Sep 27 '17 at 14:15
  • 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) – AndyG Sep 27 '17 at 15:07
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.

NPS
  • 6,003
  • 11
  • 53
  • 90
  • @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. – NPS Nov 30 '20 at 01:32
  • :D (it 's not enough to post a happy face so I have to write something more) – Moberg Nov 30 '20 at 08:51
  • My compiler didn't like the `.` with a type. However it was fine with `arr.size() * sizeof(decltype(arr)::value_type)`/ – Daniel Jan 05 '23 at 02:03
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.

Oliv
  • 17,610
  • 1
  • 29
  • 72
  • No, I asked "what is **the simplest way** of getting that size." – NPS Sep 29 '17 at 11:40
  • 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. – Oliv Sep 29 '17 at 11:48
  • I meant the simplest code, so the less writing/calculating the better. – NPS Sep 29 '17 at 12:14
  • 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. – NPS Sep 29 '17 at 12:56
  • @NPS I am adhering to this point of view. Nevertheless, when there are no better alternatives, there are no better choice! – Oliv Sep 29 '17 at 13:02
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;
}
Flow
  • 23,572
  • 15
  • 99
  • 156
-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.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 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` ? – MSalters Sep 27 '17 at 15:13