std::array over c style array - c++

I was told that in C++, one should always use std::array over c-style array.
After viewing around questions I come across people saying that std::array is better.
In that sense, I used a lot of std::array and sometimes when I use other libraries, I have to use methods that takes in c-style arrays.
For example, I am working with this function
void Draw(float* arg);
Is it possible to pass in std::array<float,4> as a parameter?
Will there be any undefined behavior if I were to pass in &vec4[0] as the parameter?
In that sense, will it be the same for multi-dimensional arrays?
With this array declared as
std::array<std::array<float,4>,4>;
Will there also be any undefined behavior if I were to pass in &mtx4[0][0] as the parameter?
Edit: Thanks for pointing out my error in the code for the multidimensional array. I edited it.

Is it possible to pass in std::array as a parameter?
Yes. The correct syntax is:
Draw(my_array.data());
Will there be any undefined behavior if I were to pass in &vec4[0] as the parameter?
No. Syntactically it is less good at making your intentions clear, but semantically it is the same.
In that sense, will it be the same for multi-dimensional arrays?
Yes, if you mean classic C multi-dimensional arrays, which are really just flat arrays associated with indexing information. No, if you mean C array-of-array.
float array2d[5][5]; // ok
float *array2d[5]; // not ok
std::array<std::array<float,5>,5> array2d; // not ok
The first has contiguous storage. The other two are arrays of pointer-to-array and have to be handled differently. There is not enough here to recommend how.
I found a reference here to another/new syntax for multi-dimensional arrays. It should provide contiguous storage.
std::array<float,5,5>; // should be ok
I really have no idea what the status of this syntax is. Perhaps others can assist.
After some further investigation of this declaration:
std::array<std::array<float,5>,5> array2d;
The storage for array2d here is all in-line, with no pointers involved. In all the cases I was able to investigate the storage appears to be contiguous, so that the memory layout is the same as for
float array2d[5][5];
This is not a requirement of the standard. A conforming implementation could insert additional information or padding such that sizeof(array<T>) is larger than sizeof(T[]) for some T. If it did then the storage layout for these two would not be the same.

Related

Convert an array of doubles to an array of structs with only double members without copying data

I am using a third-party C++ library to do some heavy lifting in Julia. On the Julia side, data is stored in an object of type Array{Float64, 2} (this is roughly similar to a 2D array of doubles). I can pass this to C++ using a pointer to a double. On the C++ side, however, data is stored in a struct called vector3:
typedef struct _vector3
{
double x, y, z;
} vector3;
My quick and dirty approach is a five-step process:
Dynamically allocate an array of structs on the C++ side
Copy input data from double* to vector3*
Do heavy lifting
Copy output data from vector3* to double*
Delete dynamically allocated arrays
Copying large amounts of data is very inefficient. Is there some arcane trickery I can use to avoid copying data from double to struct and back? I want to somehow interpret a 1D array of double (with a size that is a multiple of 3) as a 1D array of a struct with 3 double members.
Unfortunately no you cannot. And this is because of the aliasing rule that C++ has. In short if you have an object T you cannot legally access it from a pointer of incompatible type U. In this sense you cannot access an object of type double or double* via a pointer of type struct _vector3 or vice-versa.
If you dig deep enough you will find reinterpret_cast and maybe think "Oh this is exactly what I need" but it is not. No matter what trickery you do (reinterpret_cast or otherwise) to bypass the language restrictions (also known as just make it compile) the fact remains that you can legally access the object of type double only via pointers of type double.
One trick that is often used to type-pune is to use union. Legal in C it is however illegal in C++ but some compilers allow it. In your case however I don't think there is a way to use union.
The ideal situation would be to do the heavy lifting on the double* data directly. If that is feasible on your workflow.
Strictly speaking, you cannot. I asked a similar question some times ago (Aliasing struct and array the C++ way), and answers explained why direct aliasing would invoke Undefined Behaviour, and gave some hints on possible workarounds.
That being said you are already in a corner case, because the original data come from a different language. That means that the processing of that data is not covered by the C++ standard and is only defined by the implementation that you are using (gcc/version or clang/version or...)
For your implementation, it might be legal to alias an external array to a C++ struct or an external struct to a C++ array. You shuld carefully the documentation of mixed language programming for your precise implementation.
The other answers mention real issues (the conversion may not work properly). I will add a small runtime check which verifies that aliasing works, and provide a placeholder where you would call/use your copy-heavy code.
int aliasing_supported_internal() {
double testvec[6];
_vector3* testptr = (_vector3*)(void*)testvec;
// check that the pointer wasn't changed
if (testvec != (void*)testptr) return 0;
// check for structure padding
if (testvec+3 != (void*)(testptr+1)) return 0;
// TODO other checks?
return 1;
}
int aliasing_supported() {
static int cached_result = aliasing_supported_internal();
return cached_result;
}
This code converts a small array of doubles to an array of structures aliasing (not copying), then checks if it is valid. If the conversion works (the function returns 1), you are likely to be able to use the same kind of aliasing (converting via void pointer) yourself.
BEWARE THAT THE CODE CAN STILL BE BROKEN IN UNEXPECTED WAYS. The strict aliasing rules state that even the above check is undefined behavior. This may work or may fail horribly. Only conversions that are allowed to work properly are to void* and back to the original pointer type. Also, the above check may be completely wrong in multiple inheritance hierarchies or with virtual base classes (both are in a sense unsafe to convert to void* because the actual pointer value may be shifted, that is, may change due to constraints other than alignment and by quite a few bytes)

Work with a std::vector that matches the memory of an array of double

I am trying to connect two existing codebases — one in C, the other in C++. The C++ code uses std::vector whereas the other one is based on arrays of double. I would like to pass arrays of double from the C code, perform operations on std::vectors in the C++ code, and eventually have these operations reflected in the arrays of double.
Is it possible to create a std::vector that matches the memory occupied by the array of double?
I have tried several options, but they all involve the creation of a new vector and a copy of the array of double into that vector. For instance:
void fcn(double* a, int sizeofa)
{
std::vector<double> vect_a;
vect_a.assign(a, a + sizeofa);
// operations on vect_a
for (int i=0;i<sizeofa;i++) { a[i] = vect_a[i]; }
}
As noted in the comments, std::vector manages its own memory, you can't make it use some other memory as the backing store (it would have no idea what to do if the size changed, among other issues).
But you may not need a vector at all; if you're just using vector for non-dynamic size related features, it's highly likely you could just use the functions from <algorithm> to perform the same work directly on the array that you wanted to use vector's methods to accomplish.
In C++, functions requiring a container often denote the container by Iterator pairs, which are templated. This is very convenient, especially when interfacing with external libraries, because an iterator isn't a type. It is a concept, which is just an interface that defines what a type should look like. Turns out, C style pointers are valid iterators. This means that you can use any C++ function that accepts an iterator with any C array.
So, now to answering your question. In other answers, it was made clear that you cannot make a std::vector control the memory allocated by a C array because a std::vector requires full ownership over the data because it wouldn't know how to deallocate it. You can copy the C array into a vector, but there is no point in using a std::vector unless you want it's resizing capabilities.
In summary: try not to pass std::vectors into functions because iterators are more generic. If you must avoid templates (virtual function, etc) than use a C style array because those are very flexible too, you can turn a std::vector into a C array, but the other way requires a copy.
I know this is hard if you have already made your code interface with std::vectors, in which case a copy is the only possible way. Prefer C style arrays when you don't need to resize the array, and maybe in the future std::array_view

C++ using RAII to create an array

Is there a way to use RAII when creating an array in C++, or do I have to resort to manual memory management via the "new" keyword?
EDIT: By request, some additional details:
First my disclaimer: I'm fairly novice at C++.
Now the details: I simply wanted to iterate through an existing array, SomeClass source[], and parse each element into a storage array, string results[].
So to create that storage string results[], do I need to say string results[] = new string[source.size()] or is there a way to avoid the "new" keyword here via RAII techniques?
It sounds like I'm hearing vector is the way to go. Still, wondered if it's possible with a plain old array.
In C++, especially since we're talking about RAII, we really shouldn't be using C-style arrays at all. The Standard Library provides many containers with different properties that obviate most needs for C-style arrays. By default, you should be using std::vector<> unless you have an understanding of the other containers and a compelling reason not to 1.
Judging from your comments, it looks like what you're trying to do is build an array of string data. This is simple in modern C++ -- just use a std::vector <std::string>.
int main()
{
std::vector <std::string> myStrings;
myStrings.push_back ("hello");
myStrings.push_back ("goodbye");
}
This achieves all your mentioned goals of being RAII and no need to new or delete anything. It also integrates very nicely with other Standard Library facilities, such as find.
I did say "obviate most needs," emphasis mine. There is still occasional need to go old-school. I won't discuss them here since if you actually need it you already know. Which is to say, if you don't know you probably don't need it.
All that being said, std::unique_ptr does support managing C-style arrays with special syntax:
std::unique_ptr <unsigned []> myArray (new unsigned [256]);
the array managed by myArray above will be properly deleted with delete [] at destruction time.
Since there is no unique_ptr analogue to shared_ptr's make_shared, you will either have to use new to actually construct the array, or provide your own (or someone else's) implementation of make_unique
Sidebar: make_unique will be added to C++14.
1 " you should be using std::vector<> unless you have an understanding of the other containers and a compelling reason not to"
This isn't just my opinion. It's also the general (unofficial) opinion of StackOverflow as a whole, C++'s creator Bjarne Stroustup, and the C++ Standard itself (23.1.1).
std::vector<T> is an RAII array type. From the additional information you've given std::vector<string> is appropriate for your use.
string results[] = new string[source.size()]
Just as an aside about arrays, this syntax isn't correct for C++. People teaching C and C++ often teach that arrays and pointers are the same thing, but this is not true and the syntax above shows one of the ways they differ.
The actual relationship between arrays and pointers is
Arrays and pointers are distinct types
In many contexts an implicit conversion from an array to pointer is applied. The conversion results in the address of the array's first element.
pointer arithmetic is defined such that if a pointer points to an element in an array then you can get pointers to other elements of the array by adding and subtracting to the pointer value.
In a some contexts writing an array type will result in a pointer type. In particular, function parameters declared to be of array types are adjusted to be of pointer type. E.g. void foo(int[10]); is effectively identical to void foo(int*);.
So the code you show is declaring an array and initializing it with a pointer. This will result in an error because there's no conversion from pointers to arrays.
Generally you should avoid raw arrays in C++; Arrays just have too many weird rules, such as the weird function parameter rule described above, the rules about when exactly the implicit conversion is performed, prohibitions on assignment and returning arrays from functions, etc. When starting out it's probably best to just stick with the std::array template for arrays with a size known at compile time and the std::vector template for arrays with a size not known at compile time.
You can use std::vector<string> and push_back() each result string in to the vector. You don't have to use new unless you want to avoid vectors and manage memory by yourself
I think a simple template would do the trick in the general case:
template<class T>
class HeapArray {
T* ptr = nullptr;
public:
HeapArray(int size) { ptr = new T[size]; }
~HeapArray() { delete [] ptr; }
operator T*() { return ptr; }
};
You use it as:
HeapArray<std::string> results(source.size());
results[i] = "how cool is this";
basically the HeapArray object is automatically cast'd to its member pointer.

Proper type for underlying std::array

I'm pretty new to C++, so I apologize if the answer to this is obvious.
I've been writing an STL-style custom data structure as a way to improve my skills. (I actually do have a practical need for this structure as well, but I'm going a little overboard for study purposes.)
This structure needs to dynamically resize (like a vector), and in my first draft, I made the underlying "container" a C-style array and did all the allocations and de-allocations manually. I'm refactoring, and I'd like to use a C++11-style std::array as my underlying structure, just to make the code a little cleaner. My problem is that I don't know how to declare the array class member in a way that allows for resizing. Since different template parameters entail a different type, I can't just declare a member as array and then assign the same variable to an array upon resize.
I thought about declaring a member for each potential size, like
private:
array<T, 8>
array<T, 16>
array<T, 32>
...
but I don't want each of those arrays default constructing T members.
Is there a clean solution here? Or do I just have to stick with C-style arrays?
Thanks for the help.
EDIT:
After re-reading my question, I don't think it makes sense, actually. I understood that std::array's size had to be known at compile time, but for some reason my brain to infer that my goal was impossible. It seems obvious to me now that I'm stuck with C-style arrays and the heap. I think I just needed to write it out to get perfectly clear.
Thanks for your answers.
std::array represents an array whose size is known statically (i.e. at compile time), so it cannot be used in cases such as this where the size will be only known at runtime.
Simply use std::vector instead, it has a constructor that takes the size as its argument.
std::array is specifically designed not to be resizable. It's mainly a workaround for the fact that fixed-size arrays aren't first-class value types.
The only use case that I can think of is some sort of externalized or serialized object (stored on disk or delivered over socket, or something along those lines), where there is a dynamically sized component. If you already have a format defined for that, then you should probably stick with what you have. Trying to reuse std::array<> for this will not work if the sizes are not known at compile time.
If you want to refactor, what might be useful would be a template class that can take a C array as a constructor argument, but provide an STL container interface to it.

Should arrays be used in C++?

Since std::list and std::vector exist, is there a reason to use traditional C arrays in C++, or should they be avoided, just like malloc?
In C++11 where std::array is available, the answer is "yes, arrays should be avoided". Prior to C++11, you may need to use C arrays to allocate arrays in the automatic storage (i.e. on the stack).
Definitely, although with std::array in C++11, practically only for
static data. C style arrays have three important advantages over
std::vector:
They don't require dynamic allocation. For this reason, C style
arrays are to be preferred where you're likely to have a lot of very
small arrays. Say something like an n-dimension point:
template <typename T, int dims>
class Point
{
T myData[dims];
// ...
};
Typically, one might imagine a that dims will be very small (2 or 3),
T a built-in type (double), and that you might end up with
std::vector<Point> with millions of elements. You definitely don't
want millions of dynamic allocations of 3 double.
The support static initialization. This is only an issue for static
data, where something like:
struct Data { int i; char const* s; };
Data const ourData[] =
{
{ 1, "one" },
{ 2, "two" },
// ...
};
This is often preferable to using a vector (and std::string), since it
avoids all order of initialization issues; the data is pre-loaded,
before any actual code can be executed.
Finally, related to the above, the compiler can calculate the actual
size of the array from the initializers. You don't have to count them.
If you have access to C++11, std::array solves the first two issues,
and should definitely be used in preference to C style arrays in the
first case. It doesn't address the third, however, and having the
compiler dimension the array according to the number of initializers is
still a valid reason to prefer C style arrays.
Never say "never", but I'd agree that their role is greatly diminished by true data structures from STL.
I'd also say that encapsulation inside objects should minimize the impact of choices like this. If the array is a private data member, you can swap it in or out without affecting clients of your class.
I have worked on safety critical systems where you are unable to use dynamic memory allocation. The memory has to always be on the stack. Therefore in this case you would use arrays as the size is fixed at compile time.
array in c++ gives you fixed size fast alternative of dynamic sized std::vector and std::list. std::array is one of the additions in c++11. It provides the benefit of std containers while still providing the aggregate type semantics of C-style arrays.
So in c++11 i'd certainly use std::array, where it is required, over vector. But i'd avoid C style array in C++03.
Most usually, no, I can't think of a reason to use raw arrays over, say, vectors. If the code is new.
You might have to resort to using arrays if your libraries need to be compatible with code that expects arrays and raw pointers.
I know a lot of people are pointing out std::array for allocating arrays on the stack, and std::vector for the heap. But neither seem to support non-native alignment. If you're doing any kind of numeric code that you want use SSE or VPX instructions on (thus requiring 128 or 256 byte alignment respectively), C arrays would still seem to be your best bet.
I would say arrays are still useful, if you are storing a small static amount of data why not.
The only advantage of an array (of course wrapped in something that will manage automatically its deallocation when need) over std::vector I can think about is that vector cannot pass ownership of its data, unless your compiler supports C++11 and move constructors.
C style arrays are a fundamental data structure, so there will be cases when it is better to use it. For the general case, however, use the more advanced data structures that round off the corners of the underlying data. C++ allows you to do some very interesting and useful things with memory, many of which work with simple arrays.
You should use STL containers internally, but you should not pass pointers to such containers between different modules, or you will end up in dependency hell. Example:
std::string foo;
// fill foo with stuff
myExternalOutputProc(foo.c_str());
is a very good solution but not
std::string foo;
// fill foo with stuff
myExternalOutputProc(&foo);
The reason is that std::string can be implemented in many different ways but a c-style string is always a c-style string.