Is Std::Array<T, S> Guaranteed to Be Pod If T Is Pod

Is std::arrayT, S guaranteed to be POD if T is POD?

§23.3.1:

An array is an aggregate (8.5.1) that can be initialized with the syntax array a<T, N> = { initializer-list };
where initializer-list is a comma separated list of up to N elements whose types are convertible to T.

In C++03, POD was defined in terms of aggregate: a class where every subobject is native or an aggregate is POD. So, by backwards compatibility, a C++0x std::array is POD.

Or, to be anal, one can compare the bullet-points of §9/5 (defining trivial class) 9/6 (defining standard-layout) and 9/9 (combining preceding requirements into POD) with those of 8.5.1/1, which defines aggregates.

8.5.1:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal- initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

Indeed the requirements in Clause 9 cover array as long as its element type is also POD and the implementation does not declare operator= or move inside array in addition to the specifications.

To be really anal, 17.5.2.2 says

  1. For the sake of exposition, Clauses 18 through 30 and Annex D do not describe copy/move constructors, assignment operators, or (non-virtual) destructors with the same apparent semantics as those that can be generated by default (12.1, 12.4, 12.8).
  2. It is unspecified whether the implementation provides explicit definitions for such member function signa- tures, or for virtual destructors that can be generated by default.

The note in the pseudo-code for template class array is

// No explicit construct/copy/destroy for aggregate type

Does construct/copy/destroy include operator= (assignment) or move? It probably should, but I don't think, by the strictest reading, it does.

Note that this "affects" not only POD-ness, but also trivial copyability as Johannes mentions.

Is it possible to use a std::array as a data container for a POD struct?

If compiling this part of the code as C is an option, then the most elegant solution by far is to use a union. Since alignment isn't an issue here and there will be no padding. This can be done in C only, which allows type punning through unions.

typedef union
{
struct // C11 anonymous struct
{
int16_t var0;
int16_t myValue;
int16_t myParameter,
uint16_t free;
int16_t var1;
int16_t var2;
int16_t var3;
int16_t var4;
// var5 not declared on purpose
};

int16_t arr [WORD_ARR_SIZE];

} word_t;

This is how the original C code should have been written. Here all type information and special cases are handled at compile-time, and type punning from int16_t to uint16_t is well-defined and their effective types alias.

You can make an enum for the special case var5 indexing:

typedef enum
{
var0_index = 0,
myValue_index = 1,
myParameter_index = 2,
free_index = 3,
var_1index = 4,
var_2index = 5,
var_3index = 6,
var_4index = 7,
var_5index = 7,
} var_t;

word_t word =
{
// different sorts of designated initializers can be mixed:
.var0 = x,
.myValue = y,
[var5_index] = z,
};

("word" is a horrible type/variable name though, since in computer science the term word refers to a complete integer type. So please come up with something better.)

POD implications for a struct which holds an standard library container

No. Your basic assumptions are flawed. "Standard layout" is not related to templates. E.g. std::pair<T1, T2> has standard layout if and only if both T1 and T2 do. Same goes for std::array<T,N>

However, none of the Containers have standard layout. The whole point of their allocators is to have advanced memory management.

Is it safe to put an std::arrayPOD, N in a union?

First, it's important to note that merely having two objects of different types in a union is never undefined. What's undefined is to write to one and read from another, with one exception:

[C++11: 9.5/1]: [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. —end note ] [..]

Now, although it's not written out specifically anywhere that std::array fits this rule, the fact that it's an aggregate with only element members seems enough of a guarantee:

[C++11: 23.3.2.1/2]: An array is an aggregate (8.5.1) that can be initialized with the syntax:

   array<T, N> a = { initializer-list };

where initializer-list is a comma-separated list of up to N elements whose types are convertible to T.

So, it's safe not only to have the union exist in the first place, but also to read and write to either member at will.

Therefore, my conclusion is: yes; it is safe.

Is it a bad idea to replace POD C-style array with std::valarray?

The standard replacement of C-style array would be std::vector. std::valarray is some "weird" math-vector for doing number-calculation-like stuff. It is not really designed to store an array of arbitrary objects.

That being said, using std::vector is most likely a very good idea. It would fix your leaks, use the heap, is resizable, has great exception-safety and so on.

It also guarantees that the data is stored in one contiguous block of memory. You can get a pointer to said block with the data() member function or, if you are pre-C++11, with &v[0] for a non-empty vector v. You can then do your pointer business with it as usual.

Are members of a POD-struct or standard layout type guaranteed to be aligned according to their alignment requirements?

Each element of a POD struct is itself an object, and objects can only be allocated in accordance with the alignment requirements for those objects. The alignment requirements may change, though, due to the fact that something is a sub-object of another object ([basic.align]/1, 2:

1 Object types have alignment requirements (3.9.1, 3.9.2) which place restrictions on the addresses at which an object of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested using the alignment specifier (7.6.2).

2 A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to alignof(std::max_align_t) (18.2). The alignment required for a type might be different when it is used as the type of a complete object and when it is used as the type of a subobject. [Example:

struct B { long double d; };
struct D : virtual B { char c; }

When D is the type of a complete object, it will have a subobject of type B, so it must be aligned appropriately for a long double. If D appears as a subobject of another object that also has B as a virtual base class, the
B subobject might be part of a different subobject, reducing the alignment requirements on the D subobject.—end example ] The result of the alignof operator reflects the alignment requirement of the type in the
complete-object case.

[emphasis added]

Although the examples refer to a sub-object via inheritance, the normative wording just refers to sub-objects in general, so I believe the same rules apply, so on one hand you can assume that each sub-object is aligned so that it can be accessed. On the other hand, no you can't necessarily assume that will be the same alignment that alignof gives you.

[The reference is from N4296, but I believe the same applies to all recent versions. C++98/03, of course, didn't have alignof at all, but I believe the same basic principle applies--members will be aligned so they can be used, but that alignment requirement isn't necessarily the same as when they're used as independent objects.]

Is the memory in std::array contiguous?

Yes, it is contiguous, as it is basically (and actually) a type arr[10];, but with STL like interface. It also doesn't decay to a pointer on the slightest provocation.

You can safely pass &arr[0] to a function expecting a C-style array, that's the design goal of it. To use it with the STL algorithms however, just use the begin and end functions:

// either members
std::sort(arr.begin(), arr.end());
// or free from <iterator>
std::sort(std::begin(arr), std::end(arr));

For the language lawyer part, §23.3.2.1 [array.overview] p1:

The header <array> defines a class template for storing fixed-size sequences of objects. An array supports random access iterators. An instance of array<T, N> stores N elements of type T, so that size() == N is an invariant. The elements of an array are stored contiguously, meaning that if a is an array<T, N> then it obeys the identity &a[n] == &a[0] + n for all 0 <= n < N.

And §23.3.2.1 [array.overview] p2:

An array is an aggregate (8.5.1) that can be initialized with the syntax

  • array<T, N> a = { initializer-list };

Also, in p3, listing the members of std::array:

T elems[N]; // exposition only

[ Note: The member variable elems is shown for exposition only, to emphasize that array is a class aggregate. The name elems is not part of array’s interface. —end note ]

struct with variable length array in std::variant

As has been pointed out, this is not legal C++. It just wont work this way. However, if the amount of entries is bound, it might be possible to do this:

template <std::size_t N>
struct Data {
int members;
static constexpr std::size_t entries_size = N;
Entry entries[N];
}; // Of couse, you might want to use std::array<Entry,N> instead!

// ...
std::variant<Data<2>, Data<8>, Data<32>> example;

This, of course, is highly situational. If you know the incoming data will fall into either 2, 8 or 32 entries, you can specify these at compile time. If the amount of entries is completely variable, with no guarantees, use std::vector. That's what it's for.



Related Topics



Leave a reply



Submit